[PATCH 8/9] libs: Import vkd3d 1.2.

Zebediah Figura zfigura at codeweavers.com
Mon Nov 29 11:01:21 CST 2021


The source is unchanged, with one exception: the #include of "vulkan/vulkan.h"
in vkd3d.h is changed to "wine/vulkan.h". I could not find an easy way to avoid
this.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 configure.ac                                  |    3 +
 dlls/vkd3d-shader/Makefile.in                 |   14 +
 dlls/vkd3d-shader/config.h                    |  156 +
 dlls/vkd3d-shader/libvkd3d-shader-wine.spec   |   15 +
 dlls/vkd3d/Makefile.in                        |   16 +
 dlls/vkd3d/config.h                           |  156 +
 dlls/vkd3d/include/config.h.in                |  156 +
 dlls/vkd3d/include/private/list.h             |  234 +
 dlls/vkd3d/include/private/rbtree.h           |  378 +
 dlls/vkd3d/include/private/vkd3d_common.h     |  186 +
 dlls/vkd3d/include/private/vkd3d_debug.h      |  118 +
 dlls/vkd3d/include/private/vkd3d_memory.h     |   60 +
 dlls/vkd3d/include/private/vkd3d_test.h       |  410 +
 dlls/vkd3d/include/private/vkd3d_utf8.h       |   26 +
 dlls/vkd3d/include/private/vkd3d_version.h    |    1 +
 dlls/vkd3d/include/vkd3d.h                    |  243 +
 dlls/vkd3d/include/vkd3d_d3d12.h              | 7749 ++++++++++++++
 dlls/vkd3d/include/vkd3d_d3d12.idl            | 2547 +++++
 dlls/vkd3d/include/vkd3d_d3d12sdklayers.h     |  228 +
 dlls/vkd3d/include/vkd3d_d3d12sdklayers.idl   |   43 +
 dlls/vkd3d/include/vkd3d_d3dcommon.h          |  296 +
 dlls/vkd3d/include/vkd3d_d3dcommon.idl        |   95 +
 dlls/vkd3d/include/vkd3d_dxgi.h               | 1237 +++
 dlls/vkd3d/include/vkd3d_dxgi.idl             |  154 +
 dlls/vkd3d/include/vkd3d_dxgi1_2.h            |  751 ++
 dlls/vkd3d/include/vkd3d_dxgi1_2.idl          |  100 +
 dlls/vkd3d/include/vkd3d_dxgi1_3.h            |  732 ++
 dlls/vkd3d/include/vkd3d_dxgi1_3.idl          |   50 +
 dlls/vkd3d/include/vkd3d_dxgi1_4.h            |  796 ++
 dlls/vkd3d/include/vkd3d_dxgi1_4.idl          |   47 +
 dlls/vkd3d/include/vkd3d_dxgibase.h           |   49 +
 dlls/vkd3d/include/vkd3d_dxgibase.idl         |   34 +
 dlls/vkd3d/include/vkd3d_dxgiformat.h         |  156 +
 dlls/vkd3d/include/vkd3d_dxgiformat.idl       |  139 +
 dlls/vkd3d/include/vkd3d_dxgitype.h           |   57 +
 dlls/vkd3d/include/vkd3d_dxgitype.idl         |   41 +
 dlls/vkd3d/include/vkd3d_shader.h             | 1502 +++
 dlls/vkd3d/include/vkd3d_types.h              |   60 +
 dlls/vkd3d/include/vkd3d_unknown.idl          |   55 +
 dlls/vkd3d/include/vkd3d_utils.h              |   61 +
 dlls/vkd3d/include/vkd3d_windows.h            |  281 +
 dlls/vkd3d/libs/vkd3d-common/debug.c          |  363 +
 dlls/vkd3d/libs/vkd3d-common/memory.c         |   48 +
 dlls/vkd3d/libs/vkd3d-common/utf8.c           |  164 +
 dlls/vkd3d/libs/vkd3d-shader/checksum.c       |  301 +
 dlls/vkd3d/libs/vkd3d-shader/dxbc.c           | 3659 +++++++
 .../libs/vkd3d-shader/libvkd3d-shader.pc.in   |   10 +
 dlls/vkd3d/libs/vkd3d-shader/spirv.c          | 9281 +++++++++++++++++
 dlls/vkd3d/libs/vkd3d-shader/trace.c          | 1602 +++
 dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader.map |   21 +
 .../libs/vkd3d-shader/vkd3d_shader_main.c     | 1091 ++
 .../libs/vkd3d-shader/vkd3d_shader_private.h  |  989 ++
 .../libs/vkd3d-utils/libvkd3d-utils.pc.in     |   10 +
 dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils.map   |   17 +
 .../vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c |  234 +
 .../libs/vkd3d-utils/vkd3d_utils_private.h    |   39 +
 dlls/vkd3d/libs/vkd3d/command.c               | 6461 ++++++++++++
 dlls/vkd3d/libs/vkd3d/device.c                | 3857 +++++++
 dlls/vkd3d/libs/vkd3d/libvkd3d.pc.in          |   10 +
 dlls/vkd3d/libs/vkd3d/resource.c              | 4092 ++++++++
 dlls/vkd3d/libs/vkd3d/state.c                 | 3020 ++++++
 dlls/vkd3d/libs/vkd3d/utils.c                 | 1080 ++
 dlls/vkd3d/libs/vkd3d/vkd3d.map               |   27 +
 dlls/vkd3d/libs/vkd3d/vkd3d_main.c            |  641 ++
 dlls/vkd3d/libs/vkd3d/vkd3d_private.h         | 1372 +++
 dlls/vkd3d/libs/vkd3d/vkd3d_shaders.h         |  388 +
 dlls/vkd3d/libs/vkd3d/vulkan_procs.h          |  212 +
 dlls/vkd3d/libvkd3d-wine.spec                 |   20 +
 68 files changed, 58441 insertions(+)
 create mode 100644 dlls/vkd3d-shader/Makefile.in
 create mode 100644 dlls/vkd3d-shader/config.h
 create mode 100644 dlls/vkd3d-shader/libvkd3d-shader-wine.spec
 create mode 100644 dlls/vkd3d/Makefile.in
 create mode 100644 dlls/vkd3d/config.h
 create mode 100644 dlls/vkd3d/include/config.h.in
 create mode 100644 dlls/vkd3d/include/private/list.h
 create mode 100644 dlls/vkd3d/include/private/rbtree.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_common.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_debug.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_memory.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_test.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_utf8.h
 create mode 100644 dlls/vkd3d/include/private/vkd3d_version.h
 create mode 100644 dlls/vkd3d/include/vkd3d.h
 create mode 100644 dlls/vkd3d/include/vkd3d_d3d12.h
 create mode 100644 dlls/vkd3d/include/vkd3d_d3d12.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_d3d12sdklayers.h
 create mode 100644 dlls/vkd3d/include/vkd3d_d3d12sdklayers.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_d3dcommon.h
 create mode 100644 dlls/vkd3d/include/vkd3d_d3dcommon.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_2.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_2.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_3.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_3.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_4.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgi1_4.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgibase.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgibase.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgiformat.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgiformat.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgitype.h
 create mode 100644 dlls/vkd3d/include/vkd3d_dxgitype.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_shader.h
 create mode 100644 dlls/vkd3d/include/vkd3d_types.h
 create mode 100644 dlls/vkd3d/include/vkd3d_unknown.idl
 create mode 100644 dlls/vkd3d/include/vkd3d_utils.h
 create mode 100644 dlls/vkd3d/include/vkd3d_windows.h
 create mode 100644 dlls/vkd3d/libs/vkd3d-common/debug.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-common/memory.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-common/utf8.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/checksum.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/dxbc.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/libvkd3d-shader.pc.in
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/spirv.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/trace.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader.map
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
 create mode 100644 dlls/vkd3d/libs/vkd3d-utils/libvkd3d-utils.pc.in
 create mode 100644 dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils.map
 create mode 100644 dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c
 create mode 100644 dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h
 create mode 100644 dlls/vkd3d/libs/vkd3d/command.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/device.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/libvkd3d.pc.in
 create mode 100644 dlls/vkd3d/libs/vkd3d/resource.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/state.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/utils.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/vkd3d.map
 create mode 100644 dlls/vkd3d/libs/vkd3d/vkd3d_main.c
 create mode 100644 dlls/vkd3d/libs/vkd3d/vkd3d_private.h
 create mode 100644 dlls/vkd3d/libs/vkd3d/vkd3d_shaders.h
 create mode 100644 dlls/vkd3d/libs/vkd3d/vulkan_procs.h
 create mode 100644 dlls/vkd3d/libvkd3d-wine.spec

diff --git a/configure.ac b/configure.ac
index ff393285c0b..af8c34da130 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1161,6 +1161,7 @@ WINE_EXTLIB_FLAGS(MPG123, mpg123, mpg123, "-I\$(top_srcdir)/libs/mpg123/src/libm
 WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png")
 WINE_EXTLIB_FLAGS(PTHREAD, pthread, pthread, "-I\$(top_srcdir)/libs/winpthreads/include")
 WINE_EXTLIB_FLAGS(TIFF, tiff, tiff, "-I\$(top_srcdir)/libs/tiff/libtiff")
+WINE_EXTLIB_FLAGS(VKD3D, vkd3d, vkd3d-wine, "-I\$(top_srcdir)/dlls/vkd3d/include")
 WINE_EXTLIB_FLAGS(XML2, xml2, xml2, "-I\$(top_srcdir)/libs/xml2/include -DLIBXML_STATIC")
 WINE_EXTLIB_FLAGS(XSLT, xslt, xslt, "-I\$(top_srcdir)/libs/xslt -DLIBXSLT_STATIC")
 WINE_EXTLIB_FLAGS(ZLIB, zlib, z, "-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO")
@@ -3517,6 +3518,8 @@ WINE_CONFIG_MAKEFILE(dlls/version/tests)
 WINE_CONFIG_MAKEFILE(dlls/vga)
 WINE_CONFIG_MAKEFILE(dlls/virtdisk)
 WINE_CONFIG_MAKEFILE(dlls/virtdisk/tests)
+WINE_CONFIG_MAKEFILE(dlls/vkd3d)
+WINE_CONFIG_MAKEFILE(dlls/vkd3d-shader)
 WINE_CONFIG_MAKEFILE(dlls/vmm.vxd,enable_win16)
 WINE_CONFIG_MAKEFILE(dlls/vnbt.vxd,enable_win16)
 WINE_CONFIG_MAKEFILE(dlls/vnetbios.vxd,enable_win16)
diff --git a/dlls/vkd3d-shader/Makefile.in b/dlls/vkd3d-shader/Makefile.in
new file mode 100644
index 00000000000..31dbb324675
--- /dev/null
+++ b/dlls/vkd3d-shader/Makefile.in
@@ -0,0 +1,14 @@
+EXTLIB    = libvkd3d-shader-wine.dll
+IMPORTLIB = vkd3d-shader-wine
+EXTRAINCL = -I$(srcdir)/../vkd3d/include -I$(srcdir)/../vkd3d/include/private -I../../libs/spirv-headers
+PARENTSRC = ../vkd3d
+
+C_SRCS = \
+	libs/vkd3d-common/debug.c \
+	libs/vkd3d-common/memory.c \
+	libs/vkd3d-common/utf8.c \
+	libs/vkd3d-shader/checksum.c \
+	libs/vkd3d-shader/dxbc.c \
+	libs/vkd3d-shader/spirv.c \
+	libs/vkd3d-shader/trace.c \
+	libs/vkd3d-shader/vkd3d_shader_main.c
diff --git a/dlls/vkd3d-shader/config.h b/dlls/vkd3d-shader/config.h
new file mode 100644
index 00000000000..3c629956372
--- /dev/null
+++ b/dlls/vkd3d-shader/config.h
@@ -0,0 +1,156 @@
+/* include/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have __builtin_clz. */
+#define HAVE_BUILTIN_CLZ 1
+
+/* Define to 1 if you have __builtin_popcount. */
+#define HAVE_BUILTIN_POPCOUNT 1
+
+/* Define to 1 if you have the declaration of `program_invocation_name', and
+   to 0 if you don't. */
+#undef HAVE_DECL_PROGRAM_INVOCATION_NAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the `pthread_setname_np' function. */
+#undef HAVE_PTHREAD_SETNAME_NP
+
+/* Define to 1 if you have the one-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_1
+
+/* Define to 1 if you have the two-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_2
+
+/* Define to 1 if you have SPIRV-Tools. */
+#undef HAVE_SPIRV_TOOLS
+
+/* Define to 1 if you have the <spirv/unified1/GLSL.std.450.h> header file. */
+#define HAVE_SPIRV_UNIFIED1_GLSL_STD_450_H 1
+
+/* Define to 1 if you have the <spirv/unified1/spirv.h> header file. */
+#define HAVE_SPIRV_UNIFIED1_SPIRV_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have __sync_add_and_fetch. */
+#define HAVE_SYNC_ADD_AND_FETCH 1
+
+/* Define to 1 if you have __sync_sub_and_fetch. */
+#define HAVE_SYNC_SUB_AND_FETCH 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <vulkan/GLSL.std.450.h> header file. */
+#undef HAVE_VULKAN_GLSL_STD_450_H
+
+/* Define to 1 if you have the <vulkan/spirv.h> header file. */
+#undef HAVE_VULKAN_SPIRV_H
+
+/* Define to 1 if you have the <vulkan/vulkan.h> header file. */
+#undef HAVE_VULKAN_VULKAN_H
+
+/* Define to 1 if you have libxcb. */
+#undef HAVE_XCB
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#define PACKAGE "vkd3d"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "vkd3d"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "vkd3d 1.2"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "vkd3d"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.2"
+
+/* Define to the soname of the libMoltenVK library. */
+#undef SONAME_LIBMOLTENVK
+
+/* Define to the soname of the libvulkan library. */
+#define SONAME_LIBVULKAN "vulkan-1.dll"
+
+/* Define to the soname of the libvulkan-1 library. */
+#define SONAME_LIBVULKAN_1 "vulkan-1.dll"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#define VERSION "1.2"
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
diff --git a/dlls/vkd3d-shader/libvkd3d-shader-wine.spec b/dlls/vkd3d-shader/libvkd3d-shader-wine.spec
new file mode 100644
index 00000000000..f9b6ec2951d
--- /dev/null
+++ b/dlls/vkd3d-shader/libvkd3d-shader-wine.spec
@@ -0,0 +1,15 @@
+@ cdecl vkd3d_shader_compile(ptr ptr ptr)
+@ cdecl vkd3d_shader_convert_root_signature(ptr long ptr)
+@ cdecl vkd3d_shader_find_signature_element(ptr ptr long long)
+@ cdecl vkd3d_shader_free_messages(ptr)
+@ cdecl vkd3d_shader_free_root_signature(ptr)
+@ cdecl vkd3d_shader_free_scan_descriptor_info(ptr)
+@ cdecl vkd3d_shader_free_shader_code(ptr)
+@ cdecl vkd3d_shader_free_shader_signature(ptr)
+@ cdecl vkd3d_shader_get_supported_source_types(ptr)
+@ cdecl vkd3d_shader_get_supported_target_types(long ptr)
+@ cdecl vkd3d_shader_get_version(ptr ptr)
+@ cdecl vkd3d_shader_parse_input_signature(ptr ptr ptr)
+@ cdecl vkd3d_shader_parse_root_signature(ptr ptr ptr)
+@ cdecl vkd3d_shader_scan(ptr ptr)
+@ cdecl vkd3d_shader_serialize_root_signature(ptr ptr ptr)
diff --git a/dlls/vkd3d/Makefile.in b/dlls/vkd3d/Makefile.in
new file mode 100644
index 00000000000..1171b63ef94
--- /dev/null
+++ b/dlls/vkd3d/Makefile.in
@@ -0,0 +1,16 @@
+EXTLIB    = libvkd3d-wine.dll
+IMPORTLIB = vkd3d-wine
+IMPORTS   = vkd3d-shader-wine $(PTHREAD_PE_LIBS)
+EXTRAINCL = -I$(srcdir)/include -I$(srcdir)/include/private $(PTHREAD_PE_CFLAGS)
+EXTRADEFS = -DCONST_VTABLE -DWINE_NO_NAMELESS_EXTENSION -DPATH_MAX=4096
+
+C_SRCS = \
+	libs/vkd3d/command.c \
+	libs/vkd3d/device.c \
+	libs/vkd3d/resource.c \
+	libs/vkd3d/state.c \
+	libs/vkd3d/utils.c \
+	libs/vkd3d/vkd3d_main.c \
+	libs/vkd3d-common/debug.c \
+	libs/vkd3d-common/memory.c \
+	libs/vkd3d-common/utf8.c
diff --git a/dlls/vkd3d/config.h b/dlls/vkd3d/config.h
new file mode 100644
index 00000000000..855d52d5be4
--- /dev/null
+++ b/dlls/vkd3d/config.h
@@ -0,0 +1,156 @@
+/* include/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have __builtin_clz. */
+#define HAVE_BUILTIN_CLZ 1
+
+/* Define to 1 if you have __builtin_popcount. */
+#define HAVE_BUILTIN_POPCOUNT 1
+
+/* Define to 1 if you have the declaration of `program_invocation_name', and
+   to 0 if you don't. */
+#undef HAVE_DECL_PROGRAM_INVOCATION_NAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the `pthread_setname_np' function. */
+#undef HAVE_PTHREAD_SETNAME_NP
+
+/* Define to 1 if you have the one-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_1
+
+/* Define to 1 if you have the two-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_2
+
+/* Define to 1 if you have SPIRV-Tools. */
+#undef HAVE_SPIRV_TOOLS
+
+/* Define to 1 if you have the <spirv/unified1/GLSL.std.450.h> header file. */
+#define HAVE_SPIRV_UNIFIED1_GLSL_STD_450_H 1
+
+/* Define to 1 if you have the <spirv/unified1/spirv.h> header file. */
+#define HAVE_SPIRV_UNIFIED1_SPIRV_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have __sync_add_and_fetch. */
+#define HAVE_SYNC_ADD_AND_FETCH 1
+
+/* Define to 1 if you have __sync_sub_and_fetch. */
+#define HAVE_SYNC_SUB_AND_FETCH 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <vulkan/GLSL.std.450.h> header file. */
+#undef HAVE_VULKAN_GLSL_STD_450_H
+
+/* Define to 1 if you have the <vulkan/spirv.h> header file. */
+#undef HAVE_VULKAN_SPIRV_H
+
+/* Define to 1 if you have the <vulkan/vulkan.h> header file. */
+#undef HAVE_VULKAN_VULKAN_H
+
+/* Define to 1 if you have libxcb. */
+#undef HAVE_XCB
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#define PACKAGE "vkd3d"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "vkd3d"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "vkd3d 1.2"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "vkd3d"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.2"
+
+/* Define to the soname of the libMoltenVK library. */
+#undef SONAME_LIBMOLTENVK
+
+/* Define to the soname of the libvulkan library. */
+#define SONAME_LIBVULKAN "vulkan-1.dll"
+
+/* Define to the soname of the libvulkan-1 library. */
+#define SONAME_LIBVULKAN_1 "vulkan-1.dll"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Version number of package */
+#define VERSION "1.2"
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
diff --git a/dlls/vkd3d/include/config.h.in b/dlls/vkd3d/include/config.h.in
new file mode 100644
index 00000000000..2496eed1096
--- /dev/null
+++ b/dlls/vkd3d/include/config.h.in
@@ -0,0 +1,156 @@
+/* include/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have __builtin_clz. */
+#undef HAVE_BUILTIN_CLZ
+
+/* Define to 1 if you have __builtin_popcount. */
+#undef HAVE_BUILTIN_POPCOUNT
+
+/* Define to 1 if you have the declaration of `program_invocation_name', and
+   to 0 if you don't. */
+#undef HAVE_DECL_PROGRAM_INVOCATION_NAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the `pthread_setname_np' function. */
+#undef HAVE_PTHREAD_SETNAME_NP
+
+/* Define to 1 if you have the one-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_1
+
+/* Define to 1 if you have the two-argument variant of pthread_setname_np().
+   */
+#undef HAVE_PTHREAD_SETNAME_NP_2
+
+/* Define to 1 if you have SPIRV-Tools. */
+#undef HAVE_SPIRV_TOOLS
+
+/* Define to 1 if you have the <spirv/unified1/GLSL.std.450.h> header file. */
+#undef HAVE_SPIRV_UNIFIED1_GLSL_STD_450_H
+
+/* Define to 1 if you have the <spirv/unified1/spirv.h> header file. */
+#undef HAVE_SPIRV_UNIFIED1_SPIRV_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have __sync_add_and_fetch. */
+#undef HAVE_SYNC_ADD_AND_FETCH
+
+/* Define to 1 if you have __sync_sub_and_fetch. */
+#undef HAVE_SYNC_SUB_AND_FETCH
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <vulkan/GLSL.std.450.h> header file. */
+#undef HAVE_VULKAN_GLSL_STD_450_H
+
+/* Define to 1 if you have the <vulkan/spirv.h> header file. */
+#undef HAVE_VULKAN_SPIRV_H
+
+/* Define to 1 if you have the <vulkan/vulkan.h> header file. */
+#undef HAVE_VULKAN_VULKAN_H
+
+/* Define to 1 if you have libxcb. */
+#undef HAVE_XCB
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to the soname of the libMoltenVK library. */
+#undef SONAME_LIBMOLTENVK
+
+/* Define to the soname of the libvulkan library. */
+#undef SONAME_LIBVULKAN
+
+/* Define to the soname of the libvulkan-1 library. */
+#undef SONAME_LIBVULKAN_1
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/dlls/vkd3d/include/private/list.h b/dlls/vkd3d/include/private/list.h
new file mode 100644
index 00000000000..b4d681fe0f3
--- /dev/null
+++ b/dlls/vkd3d/include/private/list.h
@@ -0,0 +1,234 @@
+/*
+ * Linked lists support
+ *
+ * Copyright (C) 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_LIST_H
+#define __WINE_SERVER_LIST_H
+
+#include <stddef.h>
+
+struct list
+{
+    struct list *next;
+    struct list *prev;
+};
+
+/* Define a list like so:
+ *
+ *   struct gadget
+ *   {
+ *       struct list  entry;   <-- doesn't have to be the first item in the struct
+ *       int          a, b;
+ *   };
+ *
+ *   static struct list global_gadgets = LIST_INIT( global_gadgets );
+ *
+ * or
+ *
+ *   struct some_global_thing
+ *   {
+ *       struct list gadgets;
+ *   };
+ *
+ *   list_init( &some_global_thing->gadgets );
+ *
+ * Manipulate it like this:
+ *
+ *   list_add_head( &global_gadgets, &new_gadget->entry );
+ *   list_remove( &new_gadget->entry );
+ *   list_add_after( &some_random_gadget->entry, &new_gadget->entry );
+ *
+ * And to iterate over it:
+ *
+ *   struct gadget *gadget;
+ *   LIST_FOR_EACH_ENTRY( gadget, &global_gadgets, struct gadget, entry )
+ *   {
+ *       ...
+ *   }
+ *
+ */
+
+/* add an element after the specified one */
+static inline void list_add_after( struct list *elem, struct list *to_add )
+{
+    to_add->next = elem->next;
+    to_add->prev = elem;
+    elem->next->prev = to_add;
+    elem->next = to_add;
+}
+
+/* add an element before the specified one */
+static inline void list_add_before( struct list *elem, struct list *to_add )
+{
+    to_add->next = elem;
+    to_add->prev = elem->prev;
+    elem->prev->next = to_add;
+    elem->prev = to_add;
+}
+
+/* add element at the head of the list */
+static inline void list_add_head( struct list *list, struct list *elem )
+{
+    list_add_after( list, elem );
+}
+
+/* add element at the tail of the list */
+static inline void list_add_tail( struct list *list, struct list *elem )
+{
+    list_add_before( list, elem );
+}
+
+/* remove an element from its list */
+static inline void list_remove( struct list *elem )
+{
+    elem->next->prev = elem->prev;
+    elem->prev->next = elem->next;
+}
+
+/* get the next element */
+static inline struct list *list_next( const struct list *list, const struct list *elem )
+{
+    struct list *ret = elem->next;
+    if (elem->next == list) ret = NULL;
+    return ret;
+}
+
+/* get the previous element */
+static inline struct list *list_prev( const struct list *list, const struct list *elem )
+{
+    struct list *ret = elem->prev;
+    if (elem->prev == list) ret = NULL;
+    return ret;
+}
+
+/* get the first element */
+static inline struct list *list_head( const struct list *list )
+{
+    return list_next( list, list );
+}
+
+/* get the last element */
+static inline struct list *list_tail( const struct list *list )
+{
+    return list_prev( list, list );
+}
+
+/* check if a list is empty */
+static inline int list_empty( const struct list *list )
+{
+    return list->next == list;
+}
+
+/* initialize a list */
+static inline void list_init( struct list *list )
+{
+    list->next = list->prev = list;
+}
+
+/* count the elements of a list */
+static inline unsigned int list_count( const struct list *list )
+{
+    unsigned count = 0;
+    const struct list *ptr;
+    for (ptr = list->next; ptr != list; ptr = ptr->next) count++;
+    return count;
+}
+
+/* move all elements from src to the tail of dst */
+static inline void list_move_tail( struct list *dst, struct list *src )
+{
+    if (list_empty(src)) return;
+
+    dst->prev->next = src->next;
+    src->next->prev = dst->prev;
+    dst->prev = src->prev;
+    src->prev->next = dst;
+    list_init(src);
+}
+
+/* move all elements from src to the head of dst */
+static inline void list_move_head( struct list *dst, struct list *src )
+{
+    if (list_empty(src)) return;
+
+    dst->next->prev = src->prev;
+    src->prev->next = dst->next;
+    dst->next = src->next;
+    src->next->prev = dst;
+    list_init(src);
+}
+
+/* iterate through the list */
+#define LIST_FOR_EACH(cursor,list) \
+    for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next)
+
+/* iterate through the list, with safety against removal */
+#define LIST_FOR_EACH_SAFE(cursor, cursor2, list) \
+    for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \
+         (cursor) != (list); \
+         (cursor) = (cursor2), (cursor2) = (cursor)->next)
+
+/* iterate through the list using a list entry */
+#define LIST_FOR_EACH_ENTRY(elem, list, type, field) \
+    for ((elem) = LIST_ENTRY((list)->next, type, field); \
+         &(elem)->field != (list); \
+         (elem) = LIST_ENTRY((elem)->field.next, type, field))
+
+/* iterate through the list using a list entry, with safety against removal */
+#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field) \
+    for ((cursor) = LIST_ENTRY((list)->next, type, field), \
+         (cursor2) = LIST_ENTRY((cursor)->field.next, type, field); \
+         &(cursor)->field != (list); \
+         (cursor) = (cursor2), \
+         (cursor2) = LIST_ENTRY((cursor)->field.next, type, field))
+
+/* iterate through the list in reverse order */
+#define LIST_FOR_EACH_REV(cursor,list) \
+    for ((cursor) = (list)->prev; (cursor) != (list); (cursor) = (cursor)->prev)
+
+/* iterate through the list in reverse order, with safety against removal */
+#define LIST_FOR_EACH_SAFE_REV(cursor, cursor2, list) \
+    for ((cursor) = (list)->prev, (cursor2) = (cursor)->prev; \
+         (cursor) != (list); \
+         (cursor) = (cursor2), (cursor2) = (cursor)->prev)
+
+/* iterate through the list in reverse order using a list entry */
+#define LIST_FOR_EACH_ENTRY_REV(elem, list, type, field) \
+    for ((elem) = LIST_ENTRY((list)->prev, type, field); \
+         &(elem)->field != (list); \
+         (elem) = LIST_ENTRY((elem)->field.prev, type, field))
+
+/* iterate through the list in reverse order using a list entry, with safety against removal */
+#define LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field) \
+    for ((cursor) = LIST_ENTRY((list)->prev, type, field), \
+         (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field); \
+         &(cursor)->field != (list); \
+         (cursor) = (cursor2), \
+         (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field))
+
+/* macros for statically initialized lists */
+#undef LIST_INIT
+#define LIST_INIT(list)  { &(list), &(list) }
+
+/* get pointer to object containing list element */
+#undef LIST_ENTRY
+#define LIST_ENTRY(elem, type, field) \
+    ((type *)((char *)(elem) - offsetof(type, field)))
+
+#endif  /* __WINE_SERVER_LIST_H */
diff --git a/dlls/vkd3d/include/private/rbtree.h b/dlls/vkd3d/include/private/rbtree.h
new file mode 100644
index 00000000000..b4993da3ce5
--- /dev/null
+++ b/dlls/vkd3d/include/private/rbtree.h
@@ -0,0 +1,378 @@
+/*
+ * Red-black search tree support
+ *
+ * Copyright 2009 Henri Verbeet
+ * Copyright 2009 Andrew Riedi
+ * Copyright 2016 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_WINE_RBTREE_H
+#define __WINE_WINE_RBTREE_H
+
+#define RB_ENTRY_VALUE(element, type, field) \
+    ((type *)((char *)(element) - offsetof(type, field)))
+
+struct rb_entry
+{
+    struct rb_entry *parent;
+    struct rb_entry *left;
+    struct rb_entry *right;
+    unsigned int flags;
+};
+
+typedef int (*rb_compare_func)(const void *key, const struct rb_entry *entry);
+
+struct rb_tree
+{
+    rb_compare_func compare;
+    struct rb_entry *root;
+};
+
+typedef void (rb_traverse_func)(struct rb_entry *entry, void *context);
+
+#define RB_FLAG_RED                0x1
+
+static inline int rb_is_red(struct rb_entry *entry)
+{
+    return entry && (entry->flags & RB_FLAG_RED);
+}
+
+static inline void rb_rotate_left(struct rb_tree *tree, struct rb_entry *e)
+{
+    struct rb_entry *right = e->right;
+
+    if (!e->parent)
+        tree->root = right;
+    else if (e->parent->left == e)
+        e->parent->left = right;
+    else
+        e->parent->right = right;
+
+    e->right = right->left;
+    if (e->right) e->right->parent = e;
+    right->left = e;
+    right->parent = e->parent;
+    e->parent = right;
+}
+
+static inline void rb_rotate_right(struct rb_tree *tree, struct rb_entry *e)
+{
+    struct rb_entry *left = e->left;
+
+    if (!e->parent)
+        tree->root = left;
+    else if (e->parent->left == e)
+        e->parent->left = left;
+    else
+        e->parent->right = left;
+
+    e->left = left->right;
+    if (e->left) e->left->parent = e;
+    left->right = e;
+    left->parent = e->parent;
+    e->parent = left;
+}
+
+static inline void rb_flip_color(struct rb_entry *entry)
+{
+    entry->flags ^= RB_FLAG_RED;
+    entry->left->flags ^= RB_FLAG_RED;
+    entry->right->flags ^= RB_FLAG_RED;
+}
+
+static inline struct rb_entry *rb_head(struct rb_entry *iter)
+{
+    if (!iter) return NULL;
+    while (iter->left) iter = iter->left;
+    return iter;
+}
+
+static inline struct rb_entry *rb_next(struct rb_entry *iter)
+{
+    if (iter->right) return rb_head(iter->right);
+    while (iter->parent && iter->parent->right == iter) iter = iter->parent;
+    return iter->parent;
+}
+
+static inline struct rb_entry *rb_postorder_head(struct rb_entry *iter)
+{
+    if (!iter) return NULL;
+
+    for (;;) {
+        while (iter->left) iter = iter->left;
+        if (!iter->right) return iter;
+        iter = iter->right;
+    }
+}
+
+static inline struct rb_entry *rb_postorder_next(struct rb_entry *iter)
+{
+    if (!iter->parent) return NULL;
+    if (iter == iter->parent->right || !iter->parent->right) return iter->parent;
+    return rb_postorder_head(iter->parent->right);
+}
+
+/* iterate through the tree */
+#define RB_FOR_EACH(cursor, tree) \
+    for ((cursor) = rb_head((tree)->root); (cursor); (cursor) = rb_next(cursor))
+
+/* iterate through the tree using a tree entry */
+#define RB_FOR_EACH_ENTRY(elem, tree, type, field) \
+    for ((elem) = RB_ENTRY_VALUE(rb_head((tree)->root), type, field); \
+         &(elem)->field; \
+         (elem) = RB_ENTRY_VALUE(rb_next(&elem->field), type, field))
+
+/* iterate through the tree using using postorder, making it safe to free the entry */
+#define RB_FOR_EACH_DESTRUCTOR(cursor, cursor2, tree) \
+    for ((cursor) = rb_postorder_head((tree)->root); \
+         (cursor) && (((cursor2) = rb_postorder_next(cursor)) || 1); \
+         (cursor) = (cursor2))
+
+/* iterate through the tree using a tree entry and postorder, making it safe to free the entry */
+#define RB_FOR_EACH_ENTRY_DESTRUCTOR(elem, elem2, tree, type, field) \
+    for ((elem) = RB_ENTRY_VALUE(rb_postorder_head((tree)->root), type, field); \
+         &(elem)->field \
+             && (((elem2) = RB_ENTRY_VALUE(rb_postorder_next(&(elem)->field), type, field)) || 1); \
+         (elem) = (elem2))
+
+
+static inline void rb_postorder(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+    struct rb_entry *iter, *next;
+    RB_FOR_EACH_DESTRUCTOR(iter, next, tree) callback(iter, context);
+}
+
+static inline void rb_init(struct rb_tree *tree, rb_compare_func compare)
+{
+    tree->compare = compare;
+    tree->root = NULL;
+}
+
+static inline void rb_for_each_entry(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+    struct rb_entry *iter;
+    RB_FOR_EACH(iter, tree) callback(iter, context);
+}
+
+static inline void rb_clear(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+    /* Note that we use postorder here because the callback will likely free the entry. */
+    if (callback) rb_postorder(tree, callback, context);
+    tree->root = NULL;
+}
+
+static inline void rb_destroy(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+    rb_clear(tree, callback, context);
+}
+
+static inline struct rb_entry *rb_get(const struct rb_tree *tree, const void *key)
+{
+    struct rb_entry *entry = tree->root;
+    while (entry)
+    {
+        int c = tree->compare(key, entry);
+        if (!c) return entry;
+        entry = c < 0 ? entry->left : entry->right;
+    }
+    return NULL;
+}
+
+static inline int rb_put(struct rb_tree *tree, const void *key, struct rb_entry *entry)
+{
+    struct rb_entry **iter = &tree->root, *parent = tree->root;
+
+    while (*iter)
+    {
+        int c;
+
+        parent = *iter;
+        c = tree->compare(key, parent);
+        if (!c) return -1;
+        else if (c < 0) iter = &parent->left;
+        else iter = &parent->right;
+    }
+
+    entry->flags = RB_FLAG_RED;
+    entry->parent = parent;
+    entry->left = NULL;
+    entry->right = NULL;
+    *iter = entry;
+
+    while (rb_is_red(entry->parent))
+    {
+        if (entry->parent == entry->parent->parent->left)
+        {
+            if (rb_is_red(entry->parent->parent->right))
+            {
+                rb_flip_color(entry->parent->parent);
+                entry = entry->parent->parent;
+            }
+            else
+            {
+                if (entry == entry->parent->right)
+                {
+                    entry = entry->parent;
+                    rb_rotate_left(tree, entry);
+                }
+                entry->parent->flags &= ~RB_FLAG_RED;
+                entry->parent->parent->flags |= RB_FLAG_RED;
+                rb_rotate_right(tree, entry->parent->parent);
+            }
+        }
+        else
+        {
+            if (rb_is_red(entry->parent->parent->left))
+            {
+                rb_flip_color(entry->parent->parent);
+                entry = entry->parent->parent;
+            }
+            else
+            {
+                if (entry == entry->parent->left)
+                {
+                    entry = entry->parent;
+                    rb_rotate_right(tree, entry);
+                }
+                entry->parent->flags &= ~RB_FLAG_RED;
+                entry->parent->parent->flags |= RB_FLAG_RED;
+                rb_rotate_left(tree, entry->parent->parent);
+            }
+        }
+    }
+
+    tree->root->flags &= ~RB_FLAG_RED;
+
+    return 0;
+}
+
+static inline void rb_remove(struct rb_tree *tree, struct rb_entry *entry)
+{
+    struct rb_entry *iter, *child, *parent, *w;
+    int need_fixup;
+
+    if (entry->right && entry->left)
+        for(iter = entry->right; iter->left; iter = iter->left);
+    else
+        iter = entry;
+
+    child = iter->left ? iter->left : iter->right;
+
+    if (!iter->parent)
+        tree->root = child;
+    else if (iter == iter->parent->left)
+        iter->parent->left = child;
+    else
+        iter->parent->right = child;
+
+    if (child) child->parent = iter->parent;
+    parent = iter->parent;
+
+    need_fixup = !rb_is_red(iter);
+
+    if (entry != iter)
+    {
+        *iter = *entry;
+        if (!iter->parent)
+            tree->root = iter;
+        else if (entry == iter->parent->left)
+            iter->parent->left = iter;
+        else
+            iter->parent->right = iter;
+
+        if (iter->right) iter->right->parent = iter;
+        if (iter->left)  iter->left->parent = iter;
+        if (parent == entry) parent = iter;
+    }
+
+    if (need_fixup)
+    {
+        while (parent && !rb_is_red(child))
+        {
+            if (child == parent->left)
+            {
+                w = parent->right;
+                if (rb_is_red(w))
+                {
+                    w->flags &= ~RB_FLAG_RED;
+                    parent->flags |= RB_FLAG_RED;
+                    rb_rotate_left(tree, parent);
+                    w = parent->right;
+                }
+                if (rb_is_red(w->left) || rb_is_red(w->right))
+                {
+                    if (!rb_is_red(w->right))
+                    {
+                        w->left->flags &= ~RB_FLAG_RED;
+                        w->flags |= RB_FLAG_RED;
+                        rb_rotate_right(tree, w);
+                        w = parent->right;
+                    }
+                    w->flags = (w->flags & ~RB_FLAG_RED) | (parent->flags & RB_FLAG_RED);
+                    parent->flags &= ~RB_FLAG_RED;
+                    if (w->right)
+                        w->right->flags &= ~RB_FLAG_RED;
+                    rb_rotate_left(tree, parent);
+                    child = NULL;
+                    break;
+                }
+            }
+            else
+            {
+                w = parent->left;
+                if (rb_is_red(w))
+                {
+                    w->flags &= ~RB_FLAG_RED;
+                    parent->flags |= RB_FLAG_RED;
+                    rb_rotate_right(tree, parent);
+                    w = parent->left;
+                }
+                if (rb_is_red(w->left) || rb_is_red(w->right))
+                {
+                    if (!rb_is_red(w->left))
+                    {
+                        w->right->flags &= ~RB_FLAG_RED;
+                        w->flags |= RB_FLAG_RED;
+                        rb_rotate_left(tree, w);
+                        w = parent->left;
+                    }
+                    w->flags = (w->flags & ~RB_FLAG_RED) | (parent->flags & RB_FLAG_RED);
+                    parent->flags &= ~RB_FLAG_RED;
+                    if (w->left)
+                        w->left->flags &= ~RB_FLAG_RED;
+                    rb_rotate_right(tree, parent);
+                    child = NULL;
+                    break;
+                }
+            }
+            w->flags |= RB_FLAG_RED;
+            child = parent;
+            parent = child->parent;
+        }
+        if (child) child->flags &= ~RB_FLAG_RED;
+    }
+
+    if (tree->root) tree->root->flags &= ~RB_FLAG_RED;
+}
+
+static inline void rb_remove_key(struct rb_tree *tree, const void *key)
+{
+    struct rb_entry *entry = rb_get(tree, key);
+    if (entry) rb_remove(tree, entry);
+}
+
+#endif  /* __WINE_WINE_RBTREE_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_common.h b/dlls/vkd3d/include/private/vkd3d_common.h
new file mode 100644
index 00000000000..ac217e9eec0
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_common.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_COMMON_H
+#define __VKD3D_COMMON_H
+
+#include "config.h"
+#include "vkd3d_windows.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdbool.h>
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#endif
+
+#define DIV_ROUND_UP(a, b) ((a) % (b) == 0 ? (a) / (b) : (a) / (b) + 1)
+
+#define STATIC_ASSERT(e) extern void __VKD3D_STATIC_ASSERT__(int [(e) ? 1 : -1])
+
+#define MEMBER_SIZE(t, m) sizeof(((t *)0)->m)
+
+static inline size_t align(size_t addr, size_t alignment)
+{
+    return (addr + (alignment - 1)) & ~(alignment - 1);
+}
+
+#ifdef __GNUC__
+# define VKD3D_PRINTF_FUNC(fmt, args) __attribute__((format(printf, fmt, args)))
+# define VKD3D_UNUSED __attribute__((unused))
+#else
+# define VKD3D_PRINTF_FUNC(fmt, args)
+# define VKD3D_UNUSED
+#endif  /* __GNUC__ */
+
+static inline unsigned int vkd3d_popcount(unsigned int v)
+{
+#ifdef _MSC_VER
+    return __popcnt(v);
+#elif defined(HAVE_BUILTIN_POPCOUNT)
+    return __builtin_popcount(v);
+#else
+    v -= (v >> 1) & 0x55555555;
+    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+    return (((v + (v >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
+#endif
+}
+
+static inline bool vkd3d_bitmask_is_contiguous(unsigned int mask)
+{
+    unsigned int i, j;
+
+    for (i = 0, j = 0; i < sizeof(mask) * CHAR_BIT; ++i)
+    {
+        if (mask & (1u << i))
+            ++j;
+        else if (j)
+            break;
+    }
+
+    return vkd3d_popcount(mask) == j;
+}
+
+/* Undefined for x == 0. */
+static inline unsigned int vkd3d_log2i(unsigned int x)
+{
+#ifdef _MSC_VER
+    /* _BitScanReverse returns the index of the highest set bit,
+     * unlike clz which is 31 - index. */
+    unsigned long result;
+    _BitScanReverse(&result, x);
+    return (unsigned int)result;
+#elif defined(HAVE_BUILTIN_CLZ)
+    return __builtin_clz(x) ^ 0x1f;
+#else
+    static const unsigned int l[] =
+    {
+        ~0u, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+          4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    };
+    unsigned int i;
+
+    return (i = x >> 16) ? (x = i >> 8) ? l[x] + 24
+            : l[i] + 16 : (i = x >> 8) ? l[i] + 8 : l[x];
+#endif
+}
+
+static inline int ascii_isupper(int c)
+{
+    return 'A' <= c && c <= 'Z';
+}
+
+static inline int ascii_tolower(int c)
+{
+    return ascii_isupper(c) ? c - 'A' + 'a' : c;
+}
+
+static inline int ascii_strcasecmp(const char *a, const char *b)
+{
+    int c_a, c_b;
+
+    do
+    {
+        c_a = ascii_tolower(*a++);
+        c_b = ascii_tolower(*b++);
+    } while (c_a == c_b && c_a != '\0');
+
+    return c_a - c_b;
+}
+
+#ifndef _WIN32
+# if HAVE_SYNC_ADD_AND_FETCH
+static inline LONG InterlockedIncrement(LONG volatile *x)
+{
+    return __sync_add_and_fetch(x, 1);
+}
+# else
+#  error "InterlockedIncrement() not implemented for this platform"
+# endif  /* HAVE_SYNC_ADD_AND_FETCH */
+
+# if HAVE_SYNC_SUB_AND_FETCH
+static inline LONG InterlockedDecrement(LONG volatile *x)
+{
+    return __sync_sub_and_fetch(x, 1);
+}
+# else
+#  error "InterlockedDecrement() not implemented for this platform"
+# endif
+#endif  /* _WIN32 */
+
+#if HAVE_SYNC_ADD_AND_FETCH
+# define atomic_add_fetch(ptr, val) __sync_add_and_fetch(ptr, val)
+#elif defined(_MSC_VER)
+/* InterlockedAdd returns value after increment, like add_and_fetch. */
+# define atomic_add_fetch(ptr, val) InterlockedAdd(ptr, val)
+#else
+# error "atomic_add_fetch() not implemented for this platform"
+#endif  /* HAVE_SYNC_ADD_AND_FETCH */
+
+static inline void vkd3d_parse_version(const char *version, int *major, int *minor)
+{
+    *major = atoi(version);
+
+    while (isdigit(*version))
+        ++version;
+    if (*version == '.')
+        ++version;
+
+    *minor = atoi(version);
+}
+
+#endif  /* __VKD3D_COMMON_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_debug.h b/dlls/vkd3d/include/private/vkd3d_debug.h
new file mode 100644
index 00000000000..c37c841ae0a
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_debug.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_DEBUG_H
+#define __VKD3D_DEBUG_H
+
+#include "vkd3d_common.h"
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef VKD3D_NO_TRACE_MESSAGES
+#define TRACE(args...) do { } while (0)
+#define TRACE_ON() (false)
+#endif
+
+#ifdef VKD3D_NO_DEBUG_MESSAGES
+#define WARN(args...) do { } while (0)
+#define FIXME(args...) do { } while (0)
+#endif
+
+enum vkd3d_dbg_level
+{
+    VKD3D_DBG_LEVEL_NONE,
+    VKD3D_DBG_LEVEL_ERR,
+    VKD3D_DBG_LEVEL_FIXME,
+    VKD3D_DBG_LEVEL_WARN,
+    VKD3D_DBG_LEVEL_TRACE,
+};
+
+enum vkd3d_dbg_level vkd3d_dbg_get_level(void) DECLSPEC_HIDDEN;
+
+void vkd3d_dbg_printf(enum vkd3d_dbg_level level, const char *function,
+        const char *fmt, ...) VKD3D_PRINTF_FUNC(3, 4) DECLSPEC_HIDDEN;
+
+const char *vkd3d_dbg_sprintf(const char *fmt, ...) VKD3D_PRINTF_FUNC(1, 2) DECLSPEC_HIDDEN;
+const char *vkd3d_dbg_vsprintf(const char *fmt, va_list args) DECLSPEC_HIDDEN;
+const char *debugstr_a(const char *str) DECLSPEC_HIDDEN;
+const char *debugstr_w(const WCHAR *wstr, size_t wchar_size) DECLSPEC_HIDDEN;
+
+#define VKD3D_DBG_LOG(level) \
+        do { \
+        const enum vkd3d_dbg_level vkd3d_dbg_level = VKD3D_DBG_LEVEL_##level; \
+        VKD3D_DBG_PRINTF
+
+#define VKD3D_DBG_LOG_ONCE(first_time_level, level) \
+        do { \
+        static bool vkd3d_dbg_next_time; \
+        const enum vkd3d_dbg_level vkd3d_dbg_level = vkd3d_dbg_next_time \
+        ? VKD3D_DBG_LEVEL_##level : VKD3D_DBG_LEVEL_##first_time_level; \
+        vkd3d_dbg_next_time = true; \
+        VKD3D_DBG_PRINTF
+
+#define VKD3D_DBG_PRINTF(...) \
+        vkd3d_dbg_printf(vkd3d_dbg_level, __FUNCTION__, __VA_ARGS__); } while (0)
+
+#ifndef TRACE
+#define TRACE VKD3D_DBG_LOG(TRACE)
+#endif
+
+#ifndef WARN
+#define WARN  VKD3D_DBG_LOG(WARN)
+#endif
+
+#ifndef FIXME
+#define FIXME VKD3D_DBG_LOG(FIXME)
+#endif
+
+#define ERR   VKD3D_DBG_LOG(ERR)
+
+#ifndef TRACE_ON
+#define TRACE_ON() (vkd3d_dbg_get_level() == VKD3D_DBG_LEVEL_TRACE)
+#endif
+
+#define FIXME_ONCE VKD3D_DBG_LOG_ONCE(FIXME, WARN)
+
+#define VKD3D_DEBUG_ENV_NAME(name) const char *vkd3d_dbg_env_name = name
+
+static inline const char *debugstr_guid(const GUID *guid)
+{
+    if (!guid)
+        return "(null)";
+
+    return vkd3d_dbg_sprintf("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+            (unsigned long)guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
+            guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
+            guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+}
+
+unsigned int vkd3d_env_var_as_uint(const char *name, unsigned int default_value) DECLSPEC_HIDDEN;
+
+struct vkd3d_debug_option
+{
+    const char *name;
+    uint64_t flag;
+};
+
+bool vkd3d_debug_list_has_member(const char *string, const char *member) DECLSPEC_HIDDEN;
+uint64_t vkd3d_parse_debug_options(const char *string,
+        const struct vkd3d_debug_option *options, unsigned int option_count) DECLSPEC_HIDDEN;
+
+#endif  /* __VKD3D_DEBUG_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_memory.h b/dlls/vkd3d/include/private/vkd3d_memory.h
new file mode 100644
index 00000000000..df93abf5257
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_memory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_MEMORY_H
+#define __VKD3D_MEMORY_H
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "vkd3d_debug.h"
+
+static inline void *vkd3d_malloc(size_t size)
+{
+    void *ptr;
+    if (!(ptr = malloc(size)))
+        ERR("Out of memory.\n");
+    return ptr;
+}
+
+static inline void *vkd3d_realloc(void *ptr, size_t size)
+{
+    if (!(ptr = realloc(ptr, size)))
+        ERR("Out of memory.\n");
+    return ptr;
+}
+
+static inline void *vkd3d_calloc(size_t count, size_t size)
+{
+    void *ptr;
+    assert(count <= ~(size_t)0 / size);
+    if (!(ptr = calloc(count, size)))
+        ERR("Out of memory.\n");
+    return ptr;
+}
+
+static inline void vkd3d_free(void *ptr)
+{
+    free(ptr);
+}
+
+bool vkd3d_array_reserve(void **elements, size_t *capacity,
+        size_t element_count, size_t element_size) DECLSPEC_HIDDEN;
+
+#endif  /* __VKD3D_MEMORY_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_test.h b/dlls/vkd3d/include/private/vkd3d_test.h
new file mode 100644
index 00000000000..6b8763ddeb7
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_test.h
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_TEST_H
+#define __VKD3D_TEST_H
+
+#include "vkd3d_common.h"
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void vkd3d_test_main(int argc, char **argv);
+static const char *vkd3d_test_name;
+static const char *vkd3d_test_platform = "other";
+
+static void vkd3d_test_start_todo(bool is_todo);
+static int vkd3d_test_loop_todo(void);
+static void vkd3d_test_end_todo(void);
+
+#define START_TEST(name) \
+        static const char *vkd3d_test_name = #name; \
+        static void vkd3d_test_main(int argc, char **argv)
+
+/*
+ * Use assert_that() for conditions that should always be true.
+ * todo_if() and bug_if() do not influence assert_that().
+ */
+#define assert_that assert_that_(__LINE__)
+
+#define ok ok_(__LINE__)
+
+#define skip skip_(__LINE__)
+
+#define trace trace_(__LINE__)
+
+#define assert_that_(line) \
+        do { \
+        unsigned int vkd3d_line = line; \
+        VKD3D_TEST_ASSERT_THAT
+
+#define VKD3D_TEST_ASSERT_THAT(...) \
+        vkd3d_test_assert_that(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define ok_(line) \
+        do { \
+        unsigned int vkd3d_line = line; \
+        VKD3D_TEST_OK
+
+#define VKD3D_TEST_OK(...) \
+        vkd3d_test_ok(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define todo_(line) \
+        do { \
+        unsigned int vkd3d_line = line; \
+        VKD3D_TEST_TODO
+
+#define VKD3D_TEST_TODO(...) \
+        vkd3d_test_todo(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define skip_(line) \
+        do { \
+        unsigned int vkd3d_line = line; \
+        VKD3D_TEST_SKIP
+
+#define VKD3D_TEST_SKIP(...) \
+        vkd3d_test_skip(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define trace_(line) \
+        do { \
+        unsigned int vkd3d_line = line; \
+        VKD3D_TEST_TRACE
+
+#define VKD3D_TEST_TRACE(...) \
+        vkd3d_test_trace(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define todo_if(is_todo) \
+    for (vkd3d_test_start_todo(is_todo); vkd3d_test_loop_todo(); vkd3d_test_end_todo())
+
+#define bug_if(is_bug) \
+    for (vkd3d_test_start_bug(is_bug); vkd3d_test_loop_bug(); vkd3d_test_end_bug())
+
+#define todo todo_if(true)
+
+static struct
+{
+    LONG success_count;
+    LONG failure_count;
+    LONG skip_count;
+    LONG todo_count;
+    LONG todo_success_count;
+    LONG bug_count;
+
+    unsigned int debug_level;
+
+    unsigned int todo_level;
+    bool todo_do_loop;
+
+    unsigned int bug_level;
+    bool bug_do_loop;
+    bool bug_enabled;
+
+    const char *test_name_filter;
+    char context[1024];
+} vkd3d_test_state;
+
+static bool
+vkd3d_test_platform_is_windows(void)
+{
+    return !strcmp(vkd3d_test_platform, "windows");
+}
+
+static inline bool
+broken(bool condition)
+{
+    return condition && vkd3d_test_platform_is_windows();
+}
+
+static void
+vkd3d_test_check_assert_that(unsigned int line, bool result, const char *fmt, va_list args)
+{
+    if (result)
+    {
+        InterlockedIncrement(&vkd3d_test_state.success_count);
+        if (vkd3d_test_state.debug_level > 1)
+            printf("%s:%d%s: Test succeeded.\n", vkd3d_test_name, line, vkd3d_test_state.context);
+    }
+    else
+    {
+        InterlockedIncrement(&vkd3d_test_state.failure_count);
+        printf("%s:%d%s: Test failed: ", vkd3d_test_name, line, vkd3d_test_state.context);
+        vprintf(fmt, args);
+    }
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) VKD3D_UNUSED
+vkd3d_test_assert_that(unsigned int line, bool result, const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    vkd3d_test_check_assert_that(line, result, fmt, args);
+    va_end(args);
+}
+
+static void
+vkd3d_test_check_ok(unsigned int line, bool result, const char *fmt, va_list args)
+{
+    bool is_todo = vkd3d_test_state.todo_level && !vkd3d_test_platform_is_windows();
+    bool is_bug = vkd3d_test_state.bug_level && !vkd3d_test_platform_is_windows();
+
+    if (is_bug && vkd3d_test_state.bug_enabled)
+    {
+        InterlockedIncrement(&vkd3d_test_state.bug_count);
+        if (is_todo)
+            result = !result;
+        if (result)
+            printf("%s:%d%s: Fixed bug: ", vkd3d_test_name, line, vkd3d_test_state.context);
+        else
+            printf("%s:%d%s: Bug: ", vkd3d_test_name, line, vkd3d_test_state.context);
+        vprintf(fmt, args);
+    }
+    else if (is_todo)
+    {
+        if (result)
+        {
+            InterlockedIncrement(&vkd3d_test_state.todo_success_count);
+            printf("%s:%d%s: Todo succeeded: ", vkd3d_test_name, line, vkd3d_test_state.context);
+        }
+        else
+        {
+            InterlockedIncrement(&vkd3d_test_state.todo_count);
+            printf("%s:%d%s: Todo: ", vkd3d_test_name, line, vkd3d_test_state.context);
+        }
+        vprintf(fmt, args);
+    }
+    else
+    {
+        vkd3d_test_check_assert_that(line, result, fmt, args);
+    }
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) VKD3D_UNUSED
+vkd3d_test_ok(unsigned int line, bool result, const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    vkd3d_test_check_ok(line, result, fmt, args);
+    va_end(args);
+}
+
+static void VKD3D_PRINTF_FUNC(2, 3) VKD3D_UNUSED
+vkd3d_test_skip(unsigned int line, const char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    printf("%s:%d%s: Test skipped: ", vkd3d_test_name, line, vkd3d_test_state.context);
+    vprintf(fmt, args);
+    va_end(args);
+    InterlockedIncrement(&vkd3d_test_state.skip_count);
+}
+
+static void VKD3D_PRINTF_FUNC(2, 3) VKD3D_UNUSED
+vkd3d_test_trace(unsigned int line, const char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    printf("%s:%d%s: ", vkd3d_test_name, line, vkd3d_test_state.context);
+    vprintf(fmt, args);
+    va_end(args);
+}
+
+static void VKD3D_PRINTF_FUNC(1, 2) VKD3D_UNUSED
+vkd3d_test_debug(const char *fmt, ...)
+{
+    char buffer[512];
+    va_list args;
+    int size;
+
+    size = snprintf(buffer, sizeof(buffer), "%s: ", vkd3d_test_name);
+    if (0 < size && size < sizeof(buffer))
+    {
+        va_start(args, fmt);
+        vsnprintf(buffer + size, sizeof(buffer) - size, fmt, args);
+        va_end(args);
+    }
+    buffer[sizeof(buffer) - 1] = '\0';
+
+#ifdef _WIN32
+    OutputDebugStringA(buffer);
+#endif
+
+    if (vkd3d_test_state.debug_level > 0)
+        printf("%s\n", buffer);
+}
+
+int main(int argc, char **argv)
+{
+    const char *test_filter = getenv("VKD3D_TEST_FILTER");
+    const char *debug_level = getenv("VKD3D_TEST_DEBUG");
+    char *test_platform = getenv("VKD3D_TEST_PLATFORM");
+    const char *bug = getenv("VKD3D_TEST_BUG");
+
+    memset(&vkd3d_test_state, 0, sizeof(vkd3d_test_state));
+    vkd3d_test_state.debug_level = debug_level ? atoi(debug_level) : 0;
+    vkd3d_test_state.bug_enabled = bug ? atoi(bug) : true;
+    vkd3d_test_state.test_name_filter = test_filter;
+
+    if (test_platform)
+    {
+        test_platform = strdup(test_platform);
+        vkd3d_test_platform = test_platform;
+    }
+
+    if (vkd3d_test_state.debug_level > 1)
+        printf("Test platform: '%s'.\n", vkd3d_test_platform);
+
+    vkd3d_test_main(argc, argv);
+
+    printf("%s: %lu tests executed (%lu failures, %lu skipped, %lu todo, %lu bugs).\n",
+            vkd3d_test_name,
+            (unsigned long)(vkd3d_test_state.success_count
+            + vkd3d_test_state.failure_count + vkd3d_test_state.todo_count
+            + vkd3d_test_state.todo_success_count),
+            (unsigned long)(vkd3d_test_state.failure_count
+            + vkd3d_test_state.todo_success_count),
+            (unsigned long)vkd3d_test_state.skip_count,
+            (unsigned long)vkd3d_test_state.todo_count,
+            (unsigned long)vkd3d_test_state.bug_count);
+
+    if (test_platform)
+        free(test_platform);
+
+    return vkd3d_test_state.failure_count || vkd3d_test_state.todo_success_count;
+}
+
+#ifdef _WIN32
+static char *vkd3d_test_strdupWtoA(WCHAR *str)
+{
+    char *out;
+    int len;
+
+    if (!(len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL)))
+        return NULL;
+    if (!(out = malloc(len)))
+        return NULL;
+    WideCharToMultiByte(CP_ACP, 0, str, -1, out, len, NULL, NULL);
+
+    return out;
+}
+
+static bool running_under_wine(void)
+{
+    HMODULE module = GetModuleHandleA("ntdll.dll");
+    return module && GetProcAddress(module, "wine_server_call");
+}
+
+int wmain(int argc, WCHAR **wargv)
+{
+    char **argv;
+    int i, ret;
+
+    argv = malloc(argc * sizeof(*argv));
+    assert(argv);
+    for (i = 0; i < argc; ++i)
+    {
+        if (!(argv[i] = vkd3d_test_strdupWtoA(wargv[i])))
+            break;
+    }
+    assert(i == argc);
+
+    vkd3d_test_platform = running_under_wine() ? "wine" : "windows";
+
+    ret = main(argc, argv);
+
+    for (i = 0; i < argc; ++i)
+        free(argv[i]);
+    free(argv);
+
+    return ret;
+}
+#endif  /* _WIN32 */
+
+typedef void (*vkd3d_test_pfn)(void);
+
+static inline void vkd3d_run_test(const char *name, vkd3d_test_pfn test_pfn)
+{
+    if (vkd3d_test_state.test_name_filter && !strstr(name, vkd3d_test_state.test_name_filter))
+        return;
+
+    vkd3d_test_debug("%s", name);
+    test_pfn();
+}
+
+static inline void vkd3d_test_start_todo(bool is_todo)
+{
+    vkd3d_test_state.todo_level = (vkd3d_test_state.todo_level << 1) | is_todo;
+    vkd3d_test_state.todo_do_loop = true;
+}
+
+static inline int vkd3d_test_loop_todo(void)
+{
+    bool do_loop = vkd3d_test_state.todo_do_loop;
+    vkd3d_test_state.todo_do_loop = false;
+    return do_loop;
+}
+
+static inline void vkd3d_test_end_todo(void)
+{
+    vkd3d_test_state.todo_level >>= 1;
+}
+
+static inline void vkd3d_test_start_bug(bool is_bug)
+{
+    vkd3d_test_state.bug_level = (vkd3d_test_state.bug_level << 1) | is_bug;
+    vkd3d_test_state.bug_do_loop = true;
+}
+
+static inline int vkd3d_test_loop_bug(void)
+{
+    bool do_loop = vkd3d_test_state.bug_do_loop;
+    vkd3d_test_state.bug_do_loop = false;
+    return do_loop;
+}
+
+static inline void vkd3d_test_end_bug(void)
+{
+    vkd3d_test_state.bug_level >>= 1;
+}
+
+static inline void vkd3d_test_set_context(const char *fmt, ...)
+{
+    va_list args;
+
+    if (!fmt)
+    {
+        vkd3d_test_state.context[0] = '\0';
+        return;
+    }
+
+    vkd3d_test_state.context[0] = ':';
+    va_start(args, fmt);
+    vsnprintf(&vkd3d_test_state.context[1], sizeof(vkd3d_test_state.context) - 1, fmt, args);
+    va_end(args);
+    vkd3d_test_state.context[sizeof(vkd3d_test_state.context) - 1] = '\0';
+}
+
+#define run_test(test_pfn) \
+        vkd3d_run_test(#test_pfn, test_pfn)
+
+#endif  /* __VKD3D_TEST_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_utf8.h b/dlls/vkd3d/include/private/vkd3d_utf8.h
new file mode 100644
index 00000000000..ab32884b216
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_utf8.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_UTF8_H
+#define __VKD3D_UTF8_H
+
+#include "vkd3d_common.h"
+
+char *vkd3d_strdup_w_utf8(const WCHAR *wstr, size_t wchar_size) DECLSPEC_HIDDEN;
+
+#endif /* __VKD3D_UTF8_H */
diff --git a/dlls/vkd3d/include/private/vkd3d_version.h b/dlls/vkd3d/include/private/vkd3d_version.h
new file mode 100644
index 00000000000..7dd2f25d609
--- /dev/null
+++ b/dlls/vkd3d/include/private/vkd3d_version.h
@@ -0,0 +1 @@
+#define VKD3D_VCS_ID ""
diff --git a/dlls/vkd3d/include/vkd3d.h b/dlls/vkd3d/include/vkd3d.h
new file mode 100644
index 00000000000..db1d5cdf607
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_H
+#define __VKD3D_H
+
+#include <vkd3d_types.h>
+
+#ifndef VKD3D_NO_WIN32_TYPES
+# include <vkd3d_windows.h>
+# include <vkd3d_d3d12.h>
+#endif  /* VKD3D_NO_WIN32_TYPES */
+
+#ifndef VKD3D_NO_VULKAN_H
+# include <wine/vulkan.h>
+#endif  /* VKD3D_NO_VULKAN_H */
+
+#ifdef __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+enum vkd3d_structure_type
+{
+    /* 1.0 */
+    VKD3D_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+    VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+    VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO,
+
+    /* 1.1 */
+    VKD3D_STRUCTURE_TYPE_OPTIONAL_INSTANCE_EXTENSIONS_INFO,
+
+    /* 1.2 */
+    VKD3D_STRUCTURE_TYPE_OPTIONAL_DEVICE_EXTENSIONS_INFO,
+    VKD3D_STRUCTURE_TYPE_APPLICATION_INFO,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_STRUCTURE_TYPE),
+};
+
+enum vkd3d_api_version
+{
+    VKD3D_API_VERSION_1_0,
+    VKD3D_API_VERSION_1_1,
+    VKD3D_API_VERSION_1_2,
+};
+
+typedef HRESULT (*PFN_vkd3d_signal_event)(HANDLE event);
+
+typedef void * (*PFN_vkd3d_thread)(void *data);
+
+typedef void * (*PFN_vkd3d_create_thread)(PFN_vkd3d_thread thread_main, void *data);
+typedef HRESULT (*PFN_vkd3d_join_thread)(void *thread);
+
+struct vkd3d_instance;
+
+struct vkd3d_instance_create_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    PFN_vkd3d_signal_event pfn_signal_event;
+    PFN_vkd3d_create_thread pfn_create_thread;
+    PFN_vkd3d_join_thread pfn_join_thread;
+    size_t wchar_size;
+
+    /* If set to NULL, libvkd3d loads libvulkan. */
+    PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr;
+
+    const char * const *instance_extensions;
+    uint32_t instance_extension_count;
+};
+
+/* Extends vkd3d_instance_create_info. Available since 1.1. */
+struct vkd3d_optional_instance_extensions_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    const char * const *extensions;
+    uint32_t extension_count;
+};
+
+/* Extends vkd3d_instance_create_info. Available since 1.2. */
+struct vkd3d_application_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    const char *application_name;
+    uint32_t application_version;
+
+    const char *engine_name; /* "vkd3d" if NULL */
+    uint32_t engine_version; /* vkd3d version if engine_name is NULL */
+
+    enum vkd3d_api_version api_version;
+};
+
+struct vkd3d_device_create_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    D3D_FEATURE_LEVEL minimum_feature_level;
+
+    struct vkd3d_instance *instance;
+    const struct vkd3d_instance_create_info *instance_create_info;
+
+    VkPhysicalDevice vk_physical_device;
+
+    const char * const *device_extensions;
+    uint32_t device_extension_count;
+
+    IUnknown *parent;
+    LUID adapter_luid;
+};
+
+/* Extends vkd3d_device_create_info. Available since 1.2. */
+struct vkd3d_optional_device_extensions_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    const char * const *extensions;
+    uint32_t extension_count;
+};
+
+/* vkd3d_image_resource_create_info flags */
+#define VKD3D_RESOURCE_INITIAL_STATE_TRANSITION 0x00000001
+#define VKD3D_RESOURCE_PRESENT_STATE_TRANSITION 0x00000002
+
+struct vkd3d_image_resource_create_info
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+
+    VkImage vk_image;
+    D3D12_RESOURCE_DESC desc;
+    unsigned int flags;
+    D3D12_RESOURCE_STATES present_state;
+};
+
+#ifndef VKD3D_NO_PROTOTYPES
+
+HRESULT vkd3d_create_instance(const struct vkd3d_instance_create_info *create_info,
+        struct vkd3d_instance **instance);
+ULONG vkd3d_instance_decref(struct vkd3d_instance *instance);
+VkInstance vkd3d_instance_get_vk_instance(struct vkd3d_instance *instance);
+ULONG vkd3d_instance_incref(struct vkd3d_instance *instance);
+
+HRESULT vkd3d_create_device(const struct vkd3d_device_create_info *create_info,
+        REFIID iid, void **device);
+IUnknown *vkd3d_get_device_parent(ID3D12Device *device);
+VkDevice vkd3d_get_vk_device(ID3D12Device *device);
+VkPhysicalDevice vkd3d_get_vk_physical_device(ID3D12Device *device);
+struct vkd3d_instance *vkd3d_instance_from_device(ID3D12Device *device);
+
+uint32_t vkd3d_get_vk_queue_family_index(ID3D12CommandQueue *queue);
+VkQueue vkd3d_acquire_vk_queue(ID3D12CommandQueue *queue);
+void vkd3d_release_vk_queue(ID3D12CommandQueue *queue);
+
+HRESULT vkd3d_create_image_resource(ID3D12Device *device,
+        const struct vkd3d_image_resource_create_info *create_info, ID3D12Resource **resource);
+ULONG vkd3d_resource_decref(ID3D12Resource *resource);
+ULONG vkd3d_resource_incref(ID3D12Resource *resource);
+
+HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
+HRESULT vkd3d_create_root_signature_deserializer(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer);
+
+VkFormat vkd3d_get_vk_format(DXGI_FORMAT format);
+
+/* 1.1 */
+DXGI_FORMAT vkd3d_get_dxgi_format(VkFormat format);
+
+/* 1.2 */
+HRESULT vkd3d_serialize_versioned_root_signature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+        ID3DBlob **blob, ID3DBlob **error_blob);
+HRESULT vkd3d_create_versioned_root_signature_deserializer(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer);
+
+#endif  /* VKD3D_NO_PROTOTYPES */
+
+/*
+ * Function pointer typedefs for vkd3d functions.
+ */
+typedef HRESULT (*PFN_vkd3d_create_instance)(const struct vkd3d_instance_create_info *create_info,
+        struct vkd3d_instance **instance);
+typedef ULONG (*PFN_vkd3d_instance_decref)(struct vkd3d_instance *instance);
+typedef VkInstance (*PFN_vkd3d_instance_get_vk_instance)(struct vkd3d_instance *instance);
+typedef ULONG (*PFN_vkd3d_instance_incref)(struct vkd3d_instance *instance);
+
+typedef HRESULT (*PFN_vkd3d_create_device)(const struct vkd3d_device_create_info *create_info,
+        REFIID iid, void **device);
+typedef IUnknown * (*PFN_vkd3d_get_device_parent)(ID3D12Device *device);
+typedef VkDevice (*PFN_vkd3d_get_vk_device)(ID3D12Device *device);
+typedef VkPhysicalDevice (*PFN_vkd3d_get_vk_physical_device)(ID3D12Device *device);
+typedef struct vkd3d_instance * (*PFN_vkd3d_instance_from_device)(ID3D12Device *device);
+
+typedef uint32_t (*PFN_vkd3d_get_vk_queue_family_index)(ID3D12CommandQueue *queue);
+typedef VkQueue (*PFN_vkd3d_acquire_vk_queue)(ID3D12CommandQueue *queue);
+typedef void (*PFN_vkd3d_release_vk_queue)(ID3D12CommandQueue *queue);
+
+typedef HRESULT (*PFN_vkd3d_create_image_resource)(ID3D12Device *device,
+        const struct vkd3d_image_resource_create_info *create_info, ID3D12Resource **resource);
+typedef ULONG (*PFN_vkd3d_resource_decref)(ID3D12Resource *resource);
+typedef ULONG (*PFN_vkd3d_resource_incref)(ID3D12Resource *resource);
+
+typedef HRESULT (*PFN_vkd3d_serialize_root_signature)(const D3D12_ROOT_SIGNATURE_DESC *desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
+typedef HRESULT (*PFN_vkd3d_create_root_signature_deserializer)(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer);
+
+typedef VkFormat (*PFN_vkd3d_get_vk_format)(DXGI_FORMAT format);
+
+/* 1.1 */
+typedef DXGI_FORMAT (*PFN_vkd3d_get_dxgi_format)(VkFormat format);
+
+/* 1.2 */
+typedef HRESULT (*PFN_vkd3d_serialize_versioned_root_signature)(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+        ID3DBlob **blob, ID3DBlob **error_blob);
+typedef HRESULT (*PFN_vkd3d_create_versioned_root_signature_deserializer)(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer);
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+
+#endif  /* __VKD3D_H */
diff --git a/dlls/vkd3d/include/vkd3d_d3d12.h b/dlls/vkd3d/include/vkd3d_d3d12.h
new file mode 100644
index 00000000000..f1036f56b99
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3d12.h
@@ -0,0 +1,7749 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_d3d12.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_d3d12_h__
+#define __vkd3d_d3d12_h__
+
+/* Forward declarations */
+
+#ifndef __ID3D12Object_FWD_DEFINED__
+#define __ID3D12Object_FWD_DEFINED__
+typedef interface ID3D12Object ID3D12Object;
+#ifdef __cplusplus
+interface ID3D12Object;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12DeviceChild_FWD_DEFINED__
+#define __ID3D12DeviceChild_FWD_DEFINED__
+typedef interface ID3D12DeviceChild ID3D12DeviceChild;
+#ifdef __cplusplus
+interface ID3D12DeviceChild;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Pageable_FWD_DEFINED__
+#define __ID3D12Pageable_FWD_DEFINED__
+typedef interface ID3D12Pageable ID3D12Pageable;
+#ifdef __cplusplus
+interface ID3D12Pageable;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Heap_FWD_DEFINED__
+#define __ID3D12Heap_FWD_DEFINED__
+typedef interface ID3D12Heap ID3D12Heap;
+#ifdef __cplusplus
+interface ID3D12Heap;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Resource_FWD_DEFINED__
+#define __ID3D12Resource_FWD_DEFINED__
+typedef interface ID3D12Resource ID3D12Resource;
+#ifdef __cplusplus
+interface ID3D12Resource;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandList_FWD_DEFINED__
+#define __ID3D12CommandList_FWD_DEFINED__
+typedef interface ID3D12CommandList ID3D12CommandList;
+#ifdef __cplusplus
+interface ID3D12CommandList;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12DescriptorHeap_FWD_DEFINED__
+#define __ID3D12DescriptorHeap_FWD_DEFINED__
+typedef interface ID3D12DescriptorHeap ID3D12DescriptorHeap;
+#ifdef __cplusplus
+interface ID3D12DescriptorHeap;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12QueryHeap_FWD_DEFINED__
+#define __ID3D12QueryHeap_FWD_DEFINED__
+typedef interface ID3D12QueryHeap ID3D12QueryHeap;
+#ifdef __cplusplus
+interface ID3D12QueryHeap;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandSignature_FWD_DEFINED__
+#define __ID3D12CommandSignature_FWD_DEFINED__
+typedef interface ID3D12CommandSignature ID3D12CommandSignature;
+#ifdef __cplusplus
+interface ID3D12CommandSignature;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12GraphicsCommandList_FWD_DEFINED__
+#define __ID3D12GraphicsCommandList_FWD_DEFINED__
+typedef interface ID3D12GraphicsCommandList ID3D12GraphicsCommandList;
+#ifdef __cplusplus
+interface ID3D12GraphicsCommandList;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12GraphicsCommandList1_FWD_DEFINED__
+#define __ID3D12GraphicsCommandList1_FWD_DEFINED__
+typedef interface ID3D12GraphicsCommandList1 ID3D12GraphicsCommandList1;
+#ifdef __cplusplus
+interface ID3D12GraphicsCommandList1;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12GraphicsCommandList2_FWD_DEFINED__
+#define __ID3D12GraphicsCommandList2_FWD_DEFINED__
+typedef interface ID3D12GraphicsCommandList2 ID3D12GraphicsCommandList2;
+#ifdef __cplusplus
+interface ID3D12GraphicsCommandList2;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandQueue_FWD_DEFINED__
+#define __ID3D12CommandQueue_FWD_DEFINED__
+typedef interface ID3D12CommandQueue ID3D12CommandQueue;
+#ifdef __cplusplus
+interface ID3D12CommandQueue;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12RootSignature_FWD_DEFINED__
+#define __ID3D12RootSignature_FWD_DEFINED__
+typedef interface ID3D12RootSignature ID3D12RootSignature;
+#ifdef __cplusplus
+interface ID3D12RootSignature;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12PipelineState_FWD_DEFINED__
+#define __ID3D12PipelineState_FWD_DEFINED__
+typedef interface ID3D12PipelineState ID3D12PipelineState;
+#ifdef __cplusplus
+interface ID3D12PipelineState;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Fence_FWD_DEFINED__
+#define __ID3D12Fence_FWD_DEFINED__
+typedef interface ID3D12Fence ID3D12Fence;
+#ifdef __cplusplus
+interface ID3D12Fence;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandAllocator_FWD_DEFINED__
+#define __ID3D12CommandAllocator_FWD_DEFINED__
+typedef interface ID3D12CommandAllocator ID3D12CommandAllocator;
+#ifdef __cplusplus
+interface ID3D12CommandAllocator;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Device_FWD_DEFINED__
+#define __ID3D12Device_FWD_DEFINED__
+typedef interface ID3D12Device ID3D12Device;
+#ifdef __cplusplus
+interface ID3D12Device;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Device1_FWD_DEFINED__
+#define __ID3D12Device1_FWD_DEFINED__
+typedef interface ID3D12Device1 ID3D12Device1;
+#ifdef __cplusplus
+interface ID3D12Device1;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12RootSignatureDeserializer_FWD_DEFINED__
+#define __ID3D12RootSignatureDeserializer_FWD_DEFINED__
+typedef interface ID3D12RootSignatureDeserializer ID3D12RootSignatureDeserializer;
+#ifdef __cplusplus
+interface ID3D12RootSignatureDeserializer;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12VersionedRootSignatureDeserializer_FWD_DEFINED__
+#define __ID3D12VersionedRootSignatureDeserializer_FWD_DEFINED__
+typedef interface ID3D12VersionedRootSignatureDeserializer ID3D12VersionedRootSignatureDeserializer;
+#ifdef __cplusplus
+interface ID3D12VersionedRootSignatureDeserializer;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_windows.h>
+#include <vkd3d_dxgibase.h>
+#include <vkd3d_d3dcommon.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _D3D12_CONSTANTS
+#define _D3D12_CONSTANTS
+#define D3D12_CS_TGSM_REGISTER_COUNT (8192)
+
+#define D3D12_MAX_ROOT_COST (64)
+
+#define D3D12_VIEWPORT_BOUNDS_MAX (32767)
+
+#define D3D12_VIEWPORT_BOUNDS_MIN (-32768)
+
+#define D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT (15)
+
+#define D3D12_APPEND_ALIGNED_ELEMENT (0xffffffff)
+
+#define D3D12_DEFAULT_BLEND_FACTOR_ALPHA (1.0f)
+#define D3D12_DEFAULT_BLEND_FACTOR_BLUE (1.0f)
+#define D3D12_DEFAULT_BLEND_FACTOR_GREEN (1.0f)
+#define D3D12_DEFAULT_BLEND_FACTOR_RED (1.0f)
+#define D3D12_DEFAULT_DEPTH_BIAS (0)
+
+#define D3D12_DEFAULT_DEPTH_BIAS_CLAMP (0.0f)
+#define D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS (0.0f)
+#define D3D12_DEFAULT_STENCIL_READ_MASK (0xff)
+
+#define D3D12_DEFAULT_STENCIL_WRITE_MASK (0xff)
+
+#define D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND (0xffffffff)
+
+#define D3D12_FLOAT32_MAX (3.402823466e+38f)
+#define D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT (32)
+
+#define D3D12_UAV_SLOT_COUNT (64)
+
+#define D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT (4096)
+
+#define D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT (4096)
+
+#define D3D12_REQ_MIP_LEVELS (15)
+
+#define D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION (2048)
+
+#define D3D12_REQ_TEXTURE1D_U_DIMENSION (16384)
+
+#define D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION (2048)
+
+#define D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION (16384)
+
+#define D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION (2048)
+
+#define D3D12_REQ_TEXTURECUBE_DIMENSION (16384)
+
+#define D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES (0xffffffff)
+
+#define D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT (8)
+
+#define D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES (2048)
+
+#define D3D12_SO_BUFFER_SLOT_COUNT (4)
+
+#define D3D12_SO_DDI_REGISTER_INDEX_DENOTING_GAP (0xffffffff)
+
+#define D3D12_SO_NO_RASTERIZED_STREAM (0xffffffff)
+
+#define D3D12_SO_OUTPUT_COMPONENT_COUNT (128)
+
+#define D3D12_SO_STREAM_COUNT (4)
+
+#define D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT (256)
+
+#define D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT (4194304)
+
+#define D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT (65536)
+
+#define D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT (16)
+
+#define D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT (65536)
+
+#define D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT (4096)
+
+#define D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE (4)
+
+#define D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256)
+
+#define D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512)
+
+#define D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT (4096)
+
+#define D3D12_VS_INPUT_REGISTER_COUNT (32)
+
+#define D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE (16)
+
+#endif
+#define D3D12_SHADER_COMPONENT_MAPPING_MASK (0x7)
+
+#define D3D12_SHADER_COMPONENT_MAPPING_SHIFT (3)
+
+#define D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES (1 << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 4))
+
+typedef enum D3D12_SHADER_MIN_PRECISION_SUPPORT {
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE = 0x0,
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_10_BIT = 0x1,
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_16_BIT = 0x2
+} D3D12_SHADER_MIN_PRECISION_SUPPORT;
+typedef enum D3D12_TILED_RESOURCES_TIER {
+    D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED = 0,
+    D3D12_TILED_RESOURCES_TIER_1 = 1,
+    D3D12_TILED_RESOURCES_TIER_2 = 2,
+    D3D12_TILED_RESOURCES_TIER_3 = 3
+} D3D12_TILED_RESOURCES_TIER;
+typedef enum D3D12_RESOURCE_BINDING_TIER {
+    D3D12_RESOURCE_BINDING_TIER_1 = 1,
+    D3D12_RESOURCE_BINDING_TIER_2 = 2,
+    D3D12_RESOURCE_BINDING_TIER_3 = 3
+} D3D12_RESOURCE_BINDING_TIER;
+typedef enum D3D12_CONSERVATIVE_RASTERIZATION_TIER {
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED = 0,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_1 = 1,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_2 = 2,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_3 = 3
+} D3D12_CONSERVATIVE_RASTERIZATION_TIER;
+typedef enum D3D12_CROSS_NODE_SHARING_TIER {
+    D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED = 0,
+    D3D12_CROSS_NODE_SHARING_TIER_1_EMULATED = 1,
+    D3D12_CROSS_NODE_SHARING_TIER_1 = 2,
+    D3D12_CROSS_NODE_SHARING_TIER_2 = 3
+} D3D12_CROSS_NODE_SHARING_TIER;
+typedef enum D3D12_RESOURCE_HEAP_TIER {
+    D3D12_RESOURCE_HEAP_TIER_1 = 1,
+    D3D12_RESOURCE_HEAP_TIER_2 = 2
+} D3D12_RESOURCE_HEAP_TIER;
+typedef enum D3D12_FORMAT_SUPPORT1 {
+    D3D12_FORMAT_SUPPORT1_NONE = 0x0,
+    D3D12_FORMAT_SUPPORT1_BUFFER = 0x1,
+    D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER = 0x2,
+    D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER = 0x4,
+    D3D12_FORMAT_SUPPORT1_SO_BUFFER = 0x8,
+    D3D12_FORMAT_SUPPORT1_TEXTURE1D = 0x10,
+    D3D12_FORMAT_SUPPORT1_TEXTURE2D = 0x20,
+    D3D12_FORMAT_SUPPORT1_TEXTURE3D = 0x40,
+    D3D12_FORMAT_SUPPORT1_TEXTURECUBE = 0x80,
+    D3D12_FORMAT_SUPPORT1_SHADER_LOAD = 0x100,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE = 0x200,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON = 0x400,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_MONO_TEXT = 0x800,
+    D3D12_FORMAT_SUPPORT1_MIP = 0x1000,
+    D3D12_FORMAT_SUPPORT1_RENDER_TARGET = 0x4000,
+    D3D12_FORMAT_SUPPORT1_BLENDABLE = 0x8000,
+    D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL = 0x10000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE = 0x40000,
+    D3D12_FORMAT_SUPPORT1_DISPLAY = 0x80000,
+    D3D12_FORMAT_SUPPORT1_CAST_WITHIN_BIT_LAYOUT = 0x100000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET = 0x200000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD = 0x400000,
+    D3D12_FORMAT_SUPPORT1_SHADER_GATHER = 0x800000,
+    D3D12_FORMAT_SUPPORT1_BACK_BUFFER_CAST = 0x1000000,
+    D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW = 0x2000000,
+    D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON = 0x4000000,
+    D3D12_FORMAT_SUPPORT1_DECODER_OUTPUT = 0x8000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_OUTPUT = 0x10000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_INPUT = 0x20000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_ENCODER = 0x40000000
+} D3D12_FORMAT_SUPPORT1;
+typedef enum D3D12_FORMAT_SUPPORT2 {
+    D3D12_FORMAT_SUPPORT2_NONE = 0x0,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x1,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x2,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x4,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x8,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x10,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x20,
+    D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x40,
+    D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x80,
+    D3D12_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x100,
+    D3D12_FORMAT_SUPPORT2_TILED = 0x200,
+    D3D12_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x4000
+} D3D12_FORMAT_SUPPORT2;
+typedef enum D3D12_WRITEBUFFERIMMEDIATE_MODE {
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_DEFAULT = 0x0,
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_MARKER_IN = 0x1,
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_MARKER_OUT = 0x2
+} D3D12_WRITEBUFFERIMMEDIATE_MODE;
+typedef enum D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER {
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1 = 0x1,
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_2 = 0x2
+} D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER;
+typedef enum D3D12_SHADER_CACHE_SUPPORT_FLAGS {
+    D3D12_SHADER_CACHE_SUPPORT_NONE = 0x0,
+    D3D12_SHADER_CACHE_SUPPORT_SINGLE_PSO = 0x1,
+    D3D12_SHADER_CACHE_SUPPORT_LIBRARY = 0x2,
+    D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_INPROC_CACHE = 0x4,
+    D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_DISK_CACHE = 0x8
+} D3D12_SHADER_CACHE_SUPPORT_FLAGS;
+typedef enum D3D12_COMMAND_LIST_SUPPORT_FLAGS {
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0x0,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT = 0x1,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE = 0x2,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE = 0x4,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY = 0x8,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE = 0x10,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS = 0x20,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_ENCODE = 0x40
+} D3D12_COMMAND_LIST_SUPPORT_FLAGS;
+typedef enum D3D12_VIEW_INSTANCING_TIER {
+    D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_VIEW_INSTANCING_TIER_1 = 0x1,
+    D3D12_VIEW_INSTANCING_TIER_2 = 0x2,
+    D3D12_VIEW_INSTANCING_TIER_3 = 0x3
+} D3D12_VIEW_INSTANCING_TIER;
+typedef enum D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER {
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0 = 0x0,
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_1 = 0x1
+} D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER;
+typedef enum D3D12_HEAP_SERIALIZATION_TIER {
+    D3D12_HEAP_SERIALIZATION_TIER_0 = 0x0,
+    D3D12_HEAP_SERIALIZATION_TIER_10 = 0xa
+} D3D12_HEAP_SERIALIZATION_TIER;
+typedef enum D3D12_RENDER_PASS_TIER {
+    D3D12_RENDER_PASS_TIER_0 = 0x0,
+    D3D12_RENDER_PASS_TIER_1 = 0x1,
+    D3D12_RENDER_PASS_TIER_2 = 0x2
+} D3D12_RENDER_PASS_TIER;
+typedef enum D3D12_RAYTRACING_TIER {
+    D3D12_RAYTRACING_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_RAYTRACING_TIER_1_0 = 0xa
+} D3D12_RAYTRACING_TIER;
+#ifndef __ID3D12Fence_FWD_DEFINED__
+#define __ID3D12Fence_FWD_DEFINED__
+typedef interface ID3D12Fence ID3D12Fence;
+#ifdef __cplusplus
+interface ID3D12Fence;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12RootSignature_FWD_DEFINED__
+#define __ID3D12RootSignature_FWD_DEFINED__
+typedef interface ID3D12RootSignature ID3D12RootSignature;
+#ifdef __cplusplus
+interface ID3D12RootSignature;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Heap_FWD_DEFINED__
+#define __ID3D12Heap_FWD_DEFINED__
+typedef interface ID3D12Heap ID3D12Heap;
+#ifdef __cplusplus
+interface ID3D12Heap;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12DescriptorHeap_FWD_DEFINED__
+#define __ID3D12DescriptorHeap_FWD_DEFINED__
+typedef interface ID3D12DescriptorHeap ID3D12DescriptorHeap;
+#ifdef __cplusplus
+interface ID3D12DescriptorHeap;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Resource_FWD_DEFINED__
+#define __ID3D12Resource_FWD_DEFINED__
+typedef interface ID3D12Resource ID3D12Resource;
+#ifdef __cplusplus
+interface ID3D12Resource;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandAllocator_FWD_DEFINED__
+#define __ID3D12CommandAllocator_FWD_DEFINED__
+typedef interface ID3D12CommandAllocator ID3D12CommandAllocator;
+#ifdef __cplusplus
+interface ID3D12CommandAllocator;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12GraphicsCommandList_FWD_DEFINED__
+#define __ID3D12GraphicsCommandList_FWD_DEFINED__
+typedef interface ID3D12GraphicsCommandList ID3D12GraphicsCommandList;
+#ifdef __cplusplus
+interface ID3D12GraphicsCommandList;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12CommandQueue_FWD_DEFINED__
+#define __ID3D12CommandQueue_FWD_DEFINED__
+typedef interface ID3D12CommandQueue ID3D12CommandQueue;
+#ifdef __cplusplus
+interface ID3D12CommandQueue;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12PipelineState_FWD_DEFINED__
+#define __ID3D12PipelineState_FWD_DEFINED__
+typedef interface ID3D12PipelineState ID3D12PipelineState;
+#ifdef __cplusplus
+interface ID3D12PipelineState;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Device_FWD_DEFINED__
+#define __ID3D12Device_FWD_DEFINED__
+typedef interface ID3D12Device ID3D12Device;
+#ifdef __cplusplus
+interface ID3D12Device;
+#endif /* __cplusplus */
+#endif
+
+typedef RECT D3D12_RECT;
+typedef struct D3D12_BOX {
+    UINT left;
+    UINT top;
+    UINT front;
+    UINT right;
+    UINT bottom;
+    UINT back;
+} D3D12_BOX;
+typedef struct D3D12_VIEWPORT {
+    FLOAT TopLeftX;
+    FLOAT TopLeftY;
+    FLOAT Width;
+    FLOAT Height;
+    FLOAT MinDepth;
+    FLOAT MaxDepth;
+} D3D12_VIEWPORT;
+typedef struct D3D12_RANGE {
+    SIZE_T Begin;
+    SIZE_T End;
+} D3D12_RANGE;
+typedef struct D3D12_RANGE_UINT64 {
+    UINT64 Begin;
+    UINT64 End;
+} D3D12_RANGE_UINT64;
+typedef struct D3D12_SUBRESOURCE_RANGE_UINT64 {
+    UINT Subresource;
+    D3D12_RANGE_UINT64 Range;
+} D3D12_SUBRESOURCE_RANGE_UINT64;
+typedef struct D3D12_RESOURCE_ALLOCATION_INFO {
+    UINT64 SizeInBytes;
+    UINT64 Alignment;
+} D3D12_RESOURCE_ALLOCATION_INFO;
+typedef struct D3D12_DRAW_ARGUMENTS {
+    UINT VertexCountPerInstance;
+    UINT InstanceCount;
+    UINT StartVertexLocation;
+    UINT StartInstanceLocation;
+} D3D12_DRAW_ARGUMENTS;
+typedef struct D3D12_DRAW_INDEXED_ARGUMENTS {
+    UINT IndexCountPerInstance;
+    UINT InstanceCount;
+    UINT StartIndexLocation;
+    INT BaseVertexLocation;
+    UINT StartInstanceLocation;
+} D3D12_DRAW_INDEXED_ARGUMENTS;
+typedef struct D3D12_DISPATCH_ARGUMENTS {
+    UINT ThreadGroupCountX;
+    UINT ThreadGroupCountY;
+    UINT ThreadGroupCountZ;
+} D3D12_DISPATCH_ARGUMENTS;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS {
+    BOOL DoublePrecisionFloatShaderOps;
+    BOOL OutputMergerLogicOp;
+    D3D12_SHADER_MIN_PRECISION_SUPPORT MinPrecisionSupport;
+    D3D12_TILED_RESOURCES_TIER TiledResourcesTier;
+    D3D12_RESOURCE_BINDING_TIER ResourceBindingTier;
+    BOOL PSSpecifiedStencilRefSupported;
+    BOOL TypedUAVLoadAdditionalFormats;
+    BOOL ROVsSupported;
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER ConservativeRasterizationTier;
+    UINT MaxGPUVirtualAddressBitsPerResource;
+    BOOL StandardSwizzle64KBSupported;
+    D3D12_CROSS_NODE_SHARING_TIER CrossNodeSharingTier;
+    BOOL CrossAdapterRowMajorTextureSupported;
+    BOOL VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation;
+    D3D12_RESOURCE_HEAP_TIER ResourceHeapTier;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS;
+typedef struct D3D12_FEATURE_DATA_FORMAT_SUPPORT {
+    DXGI_FORMAT Format;
+    D3D12_FORMAT_SUPPORT1 Support1;
+    D3D12_FORMAT_SUPPORT2 Support2;
+} D3D12_FEATURE_DATA_FORMAT_SUPPORT;
+typedef enum D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS {
+    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE = 0x0,
+    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_TILED_RESOURCE = 0x1
+} D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS;
+typedef struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
+    DXGI_FORMAT Format;
+    UINT SampleCount;
+    D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags;
+    UINT NumQualityLevels;
+} D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;
+typedef enum D3D12_HEAP_TYPE {
+    D3D12_HEAP_TYPE_DEFAULT = 1,
+    D3D12_HEAP_TYPE_UPLOAD = 2,
+    D3D12_HEAP_TYPE_READBACK = 3,
+    D3D12_HEAP_TYPE_CUSTOM = 4
+} D3D12_HEAP_TYPE;
+typedef enum D3D12_CPU_PAGE_PROPERTY {
+    D3D12_CPU_PAGE_PROPERTY_UNKNOWN = 0,
+    D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE = 1,
+    D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE = 2,
+    D3D12_CPU_PAGE_PROPERTY_WRITE_BACK = 3
+} D3D12_CPU_PAGE_PROPERTY;
+typedef enum D3D12_MEMORY_POOL {
+    D3D12_MEMORY_POOL_UNKNOWN = 0,
+    D3D12_MEMORY_POOL_L0 = 1,
+    D3D12_MEMORY_POOL_L1 = 2
+} D3D12_MEMORY_POOL;
+typedef struct D3D12_HEAP_PROPERTIES {
+    D3D12_HEAP_TYPE Type;
+    D3D12_CPU_PAGE_PROPERTY CPUPageProperty;
+    D3D12_MEMORY_POOL MemoryPoolPreference;
+    UINT CreationNodeMask;
+    UINT VisibleNodeMask;
+} D3D12_HEAP_PROPERTIES;
+typedef enum D3D12_HEAP_FLAGS {
+    D3D12_HEAP_FLAG_NONE = 0x0,
+    D3D12_HEAP_FLAG_SHARED = 0x1,
+    D3D12_HEAP_FLAG_DENY_BUFFERS = 0x4,
+    D3D12_HEAP_FLAG_ALLOW_DISPLAY = 0x8,
+    D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER = 0x20,
+    D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES = 0x40,
+    D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES = 0x80,
+    D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES = 0x0,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS = 0xc0,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES = 0x44,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES = 0x84
+} D3D12_HEAP_FLAGS;
+typedef struct D3D12_HEAP_DESC {
+    UINT64 SizeInBytes;
+    D3D12_HEAP_PROPERTIES Properties;
+    UINT64 Alignment;
+    D3D12_HEAP_FLAGS Flags;
+} D3D12_HEAP_DESC;
+typedef struct D3D12_TILED_RESOURCE_COORDINATE {
+    UINT X;
+    UINT Y;
+    UINT Z;
+    UINT Subresource;
+} D3D12_TILED_RESOURCE_COORDINATE;
+typedef struct D3D12_TILE_REGION_SIZE {
+    UINT NumTiles;
+    BOOL UseBox;
+    UINT Width;
+    UINT16 Height;
+    UINT16 Depth;
+} D3D12_TILE_REGION_SIZE;
+typedef struct D3D12_SUBRESOURCE_TILING {
+    UINT WidthInTiles;
+    UINT16 HeightInTiles;
+    UINT16 DepthInTiles;
+    UINT StartTileIndexInOverallResource;
+} D3D12_SUBRESOURCE_TILING;
+typedef struct D3D12_TILE_SHAPE {
+    UINT WidthInTexels;
+    UINT HeightInTexels;
+    UINT DepthInTexels;
+} D3D12_TILE_SHAPE;
+typedef struct D3D12_SHADER_BYTECODE {
+    const void *pShaderBytecode;
+    SIZE_T BytecodeLength;
+} D3D12_SHADER_BYTECODE;
+typedef struct D3D12_DEPTH_STENCIL_VALUE {
+    FLOAT Depth;
+    UINT8 Stencil;
+} D3D12_DEPTH_STENCIL_VALUE;
+typedef struct D3D12_CLEAR_VALUE {
+    DXGI_FORMAT Format;
+    __C89_NAMELESS union {
+        FLOAT Color[4];
+        D3D12_DEPTH_STENCIL_VALUE DepthStencil;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_CLEAR_VALUE;
+typedef struct D3D12_PACKED_MIP_INFO {
+    UINT8 NumStandardMips;
+    UINT8 NumPackedMips;
+    UINT NumTilesForPackedMips;
+    UINT StartTileIndexInOverallResource;
+} D3D12_PACKED_MIP_INFO;
+typedef enum D3D12_RESOURCE_STATES {
+    D3D12_RESOURCE_STATE_COMMON = 0,
+    D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER = 0x1,
+    D3D12_RESOURCE_STATE_INDEX_BUFFER = 0x2,
+    D3D12_RESOURCE_STATE_RENDER_TARGET = 0x4,
+    D3D12_RESOURCE_STATE_UNORDERED_ACCESS = 0x8,
+    D3D12_RESOURCE_STATE_DEPTH_WRITE = 0x10,
+    D3D12_RESOURCE_STATE_DEPTH_READ = 0x20,
+    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE = 0x40,
+    D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE = 0x80,
+    D3D12_RESOURCE_STATE_STREAM_OUT = 0x100,
+    D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT = 0x200,
+    D3D12_RESOURCE_STATE_COPY_DEST = 0x400,
+    D3D12_RESOURCE_STATE_COPY_SOURCE = 0x800,
+    D3D12_RESOURCE_STATE_RESOLVE_DEST = 0x1000,
+    D3D12_RESOURCE_STATE_RESOLVE_SOURCE = 0x2000,
+    D3D12_RESOURCE_STATE_GENERIC_READ = ((((0x1 | 0x2) | 0x40) | 0x80) | 0x200) | 0x800,
+    D3D12_RESOURCE_STATE_PRESENT = 0x0,
+    D3D12_RESOURCE_STATE_PREDICATION = 0x200
+} D3D12_RESOURCE_STATES;
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_RESOURCE_STATES);
+typedef enum D3D12_RESOURCE_BARRIER_TYPE {
+    D3D12_RESOURCE_BARRIER_TYPE_TRANSITION = 0,
+    D3D12_RESOURCE_BARRIER_TYPE_ALIASING = 1,
+    D3D12_RESOURCE_BARRIER_TYPE_UAV = 2
+} D3D12_RESOURCE_BARRIER_TYPE;
+typedef enum D3D12_RESOURCE_BARRIER_FLAGS {
+    D3D12_RESOURCE_BARRIER_FLAG_NONE = 0x0,
+    D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY = 0x1,
+    D3D12_RESOURCE_BARRIER_FLAG_END_ONLY = 0x2
+} D3D12_RESOURCE_BARRIER_FLAGS;
+typedef struct D3D12_RESOURCE_TRANSITION_BARRIER {
+    ID3D12Resource *pResource;
+    UINT Subresource;
+    D3D12_RESOURCE_STATES StateBefore;
+    D3D12_RESOURCE_STATES StateAfter;
+} D3D12_RESOURCE_TRANSITION_BARRIER;
+typedef struct D3D12_RESOURCE_ALIASING_BARRIER_ALIASING {
+    ID3D12Resource *pResourceBefore;
+    ID3D12Resource *pResourceAfter;
+} D3D12_RESOURCE_ALIASING_BARRIER;
+typedef struct D3D12_RESOURCE_UAV_BARRIER {
+    ID3D12Resource *pResource;
+} D3D12_RESOURCE_UAV_BARRIER;
+typedef struct D3D12_RESOURCE_BARRIER {
+    D3D12_RESOURCE_BARRIER_TYPE Type;
+    D3D12_RESOURCE_BARRIER_FLAGS Flags;
+    __C89_NAMELESS union {
+        D3D12_RESOURCE_TRANSITION_BARRIER Transition;
+        D3D12_RESOURCE_ALIASING_BARRIER Aliasing;
+        D3D12_RESOURCE_UAV_BARRIER UAV;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_RESOURCE_BARRIER;
+typedef enum D3D12_RESOURCE_DIMENSION {
+    D3D12_RESOURCE_DIMENSION_UNKNOWN = 0,
+    D3D12_RESOURCE_DIMENSION_BUFFER = 1,
+    D3D12_RESOURCE_DIMENSION_TEXTURE1D = 2,
+    D3D12_RESOURCE_DIMENSION_TEXTURE2D = 3,
+    D3D12_RESOURCE_DIMENSION_TEXTURE3D = 4
+} D3D12_RESOURCE_DIMENSION;
+typedef enum D3D12_TEXTURE_LAYOUT {
+    D3D12_TEXTURE_LAYOUT_UNKNOWN = 0,
+    D3D12_TEXTURE_LAYOUT_ROW_MAJOR = 1,
+    D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE = 2,
+    D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE = 3
+} D3D12_TEXTURE_LAYOUT;
+typedef enum D3D12_RESOURCE_FLAGS {
+    D3D12_RESOURCE_FLAG_NONE = 0x0,
+    D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET = 0x1,
+    D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL = 0x2,
+    D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS = 0x4,
+    D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE = 0x8,
+    D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER = 0x10,
+    D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS = 0x20
+} D3D12_RESOURCE_FLAGS;
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_RESOURCE_FLAGS);
+typedef struct D3D12_RESOURCE_DESC {
+    D3D12_RESOURCE_DIMENSION Dimension;
+    UINT64 Alignment;
+    UINT64 Width;
+    UINT Height;
+    UINT16 DepthOrArraySize;
+    UINT16 MipLevels;
+    DXGI_FORMAT Format;
+    DXGI_SAMPLE_DESC SampleDesc;
+    D3D12_TEXTURE_LAYOUT Layout;
+    D3D12_RESOURCE_FLAGS Flags;
+} D3D12_RESOURCE_DESC;
+typedef enum D3D12_RESOLVE_MODE {
+    D3D12_RESOLVE_MODE_DECOMPRESS = 0,
+    D3D12_RESOLVE_MODE_MIN = 1,
+    D3D12_RESOLVE_MODE_MAX = 2,
+    D3D12_RESOLVE_MODE_AVERAGE = 3
+} D3D12_RESOLVE_MODE;
+typedef struct D3D12_SAMPLE_POSITION {
+    INT8 X;
+    INT8 Y;
+} D3D12_SAMPLE_POSITION;
+typedef enum D3D12_TEXTURE_COPY_TYPE {
+    D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX = 0,
+    D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT = 1
+} D3D12_TEXTURE_COPY_TYPE;
+typedef struct D3D12_SUBRESOURCE_FOOTPRINT {
+    DXGI_FORMAT Format;
+    UINT Width;
+    UINT Height;
+    UINT Depth;
+    UINT RowPitch;
+} D3D12_SUBRESOURCE_FOOTPRINT;
+typedef struct D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
+    UINT64 Offset;
+    D3D12_SUBRESOURCE_FOOTPRINT Footprint;
+} D3D12_PLACED_SUBRESOURCE_FOOTPRINT;
+typedef struct D3D12_TEXTURE_COPY_LOCATION {
+    ID3D12Resource *pResource;
+    D3D12_TEXTURE_COPY_TYPE Type;
+    __C89_NAMELESS union {
+        D3D12_PLACED_SUBRESOURCE_FOOTPRINT PlacedFootprint;
+        UINT SubresourceIndex;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_TEXTURE_COPY_LOCATION;
+typedef enum D3D12_DESCRIPTOR_RANGE_TYPE {
+    D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0,
+    D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1,
+    D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2,
+    D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3
+} D3D12_DESCRIPTOR_RANGE_TYPE;
+typedef struct D3D12_DESCRIPTOR_RANGE {
+    D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
+    UINT NumDescriptors;
+    UINT BaseShaderRegister;
+    UINT RegisterSpace;
+    UINT OffsetInDescriptorsFromTableStart;
+} D3D12_DESCRIPTOR_RANGE;
+typedef enum D3D12_DESCRIPTOR_RANGE_FLAGS {
+    D3D12_DESCRIPTOR_RANGE_FLAG_NONE = 0x0,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE = 0x1,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE = 0x2,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC = 0x8
+} D3D12_DESCRIPTOR_RANGE_FLAGS;
+typedef struct D3D12_DESCRIPTOR_RANGE1 {
+    D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
+    UINT NumDescriptors;
+    UINT BaseShaderRegister;
+    UINT RegisterSpace;
+    D3D12_DESCRIPTOR_RANGE_FLAGS Flags;
+    UINT OffsetInDescriptorsFromTableStart;
+} D3D12_DESCRIPTOR_RANGE1;
+typedef struct D3D12_ROOT_DESCRIPTOR_TABLE {
+    UINT NumDescriptorRanges;
+    const D3D12_DESCRIPTOR_RANGE *pDescriptorRanges;
+} D3D12_ROOT_DESCRIPTOR_TABLE;
+typedef struct D3D12_ROOT_DESCRIPTOR_TABLE1 {
+    UINT NumDescriptorRanges;
+    const D3D12_DESCRIPTOR_RANGE1 *pDescriptorRanges;
+} D3D12_ROOT_DESCRIPTOR_TABLE1;
+typedef struct D3D12_ROOT_CONSTANTS {
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    UINT Num32BitValues;
+} D3D12_ROOT_CONSTANTS;
+typedef struct D3D12_ROOT_DESCRIPTOR {
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+} D3D12_ROOT_DESCRIPTOR;
+typedef enum D3D12_ROOT_DESCRIPTOR_FLAGS {
+    D3D12_ROOT_DESCRIPTOR_FLAG_NONE = 0x0,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE = 0x2,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC = 0x8
+} D3D12_ROOT_DESCRIPTOR_FLAGS;
+typedef struct D3D12_ROOT_DESCRIPTOR1 {
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    D3D12_ROOT_DESCRIPTOR_FLAGS Flags;
+} D3D12_ROOT_DESCRIPTOR1;
+typedef enum D3D12_ROOT_PARAMETER_TYPE {
+    D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE = 0,
+    D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS = 1,
+    D3D12_ROOT_PARAMETER_TYPE_CBV = 2,
+    D3D12_ROOT_PARAMETER_TYPE_SRV = 3,
+    D3D12_ROOT_PARAMETER_TYPE_UAV = 4
+} D3D12_ROOT_PARAMETER_TYPE;
+typedef enum D3D12_SHADER_VISIBILITY {
+    D3D12_SHADER_VISIBILITY_ALL = 0,
+    D3D12_SHADER_VISIBILITY_VERTEX = 1,
+    D3D12_SHADER_VISIBILITY_HULL = 2,
+    D3D12_SHADER_VISIBILITY_DOMAIN = 3,
+    D3D12_SHADER_VISIBILITY_GEOMETRY = 4,
+    D3D12_SHADER_VISIBILITY_PIXEL = 5
+} D3D12_SHADER_VISIBILITY;
+typedef struct D3D12_ROOT_PARAMETER {
+    D3D12_ROOT_PARAMETER_TYPE ParameterType;
+    __C89_NAMELESS union {
+        D3D12_ROOT_DESCRIPTOR_TABLE DescriptorTable;
+        D3D12_ROOT_CONSTANTS Constants;
+        D3D12_ROOT_DESCRIPTOR Descriptor;
+    } __C89_NAMELESSUNIONNAME;
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_ROOT_PARAMETER;
+typedef struct D3D12_ROOT_PARAMETER1 {
+    D3D12_ROOT_PARAMETER_TYPE ParameterType;
+    __C89_NAMELESS union {
+        D3D12_ROOT_DESCRIPTOR_TABLE1 DescriptorTable;
+        D3D12_ROOT_CONSTANTS Constants;
+        D3D12_ROOT_DESCRIPTOR1 Descriptor;
+    } __C89_NAMELESSUNIONNAME;
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_ROOT_PARAMETER1;
+typedef enum D3D12_STATIC_BORDER_COLOR {
+    D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK = 0,
+    D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK = 1,
+    D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE = 2
+} D3D12_STATIC_BORDER_COLOR;
+typedef enum D3D12_FILTER {
+    D3D12_FILTER_MIN_MAG_MIP_POINT = 0x0,
+    D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1,
+    D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4,
+    D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5,
+    D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10,
+    D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11,
+    D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14,
+    D3D12_FILTER_MIN_MAG_MIP_LINEAR = 0x15,
+    D3D12_FILTER_ANISOTROPIC = 0x55,
+    D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80,
+    D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81,
+    D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84,
+    D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85,
+    D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90,
+    D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91,
+    D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94,
+    D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95,
+    D3D12_FILTER_COMPARISON_ANISOTROPIC = 0xd5,
+    D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT = 0x100,
+    D3D12_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x101,
+    D3D12_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x104,
+    D3D12_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x105,
+    D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x110,
+    D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x111,
+    D3D12_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x114,
+    D3D12_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR = 0x115,
+    D3D12_FILTER_MINIMUM_ANISOTROPIC = 0x155,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT = 0x180,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x181,
+    D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x184,
+    D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x185,
+    D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x190,
+    D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x191,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x194,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR = 0x195,
+    D3D12_FILTER_MAXIMUM_ANISOTROPIC = 0x1d5
+} D3D12_FILTER;
+typedef enum D3D12_FILTER_TYPE {
+    D3D12_FILTER_TYPE_POINT = 0,
+    D3D12_FILTER_TYPE_LINEAR = 1
+} D3D12_FILTER_TYPE;
+#define D3D12_MIP_FILTER_SHIFT (0)
+
+#define D3D12_MAG_FILTER_SHIFT (2)
+
+#define D3D12_MIN_FILTER_SHIFT (4)
+
+#define D3D12_FILTER_TYPE_MASK (0x3)
+
+#define D3D12_ANISOTROPIC_FILTERING_BIT (0x40)
+
+typedef enum D3D12_FILTER_REDUCTION_TYPE {
+    D3D12_FILTER_REDUCTION_TYPE_STANDARD = 0,
+    D3D12_FILTER_REDUCTION_TYPE_COMPARISON = 1,
+    D3D12_FILTER_REDUCTION_TYPE_MINIMUM = 2,
+    D3D12_FILTER_REDUCTION_TYPE_MAXIMUM = 3
+} D3D12_FILTER_REDUCTION_TYPE;
+#define D3D12_FILTER_REDUCTION_TYPE_MASK (0x3)
+
+#define D3D12_FILTER_REDUCTION_TYPE_SHIFT (7)
+
+#define D3D12_DECODE_MAG_FILTER(filter) \
+    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MAG_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))
+#define D3D12_DECODE_MIN_FILTER(filter) \
+    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MIN_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))
+#define D3D12_DECODE_MIP_FILTER(filter) \
+    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MIP_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))
+#define D3D12_DECODE_IS_ANISOTROPIC_FILTER(filter)  \
+    (((filter) & D3D12_ANISOTROPIC_FILTERING_BIT) \
+    && (D3D12_DECODE_MIN_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR) \
+    && (D3D12_DECODE_MAG_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR) \
+    && (D3D12_DECODE_MIP_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR))
+#define D3D12_DECODE_FILTER_REDUCTION(filter) \
+    ((D3D12_FILTER_REDUCTION_TYPE)(((filter) >> D3D12_FILTER_REDUCTION_TYPE_SHIFT) \
+    & D3D12_FILTER_REDUCTION_TYPE_MASK))
+#define D3D12_DECODE_IS_COMPARISON_FILTER(filter) \
+    (D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_COMPARISON)
+typedef enum D3D12_TEXTURE_ADDRESS_MODE {
+    D3D12_TEXTURE_ADDRESS_MODE_WRAP = 1,
+    D3D12_TEXTURE_ADDRESS_MODE_MIRROR = 2,
+    D3D12_TEXTURE_ADDRESS_MODE_CLAMP = 3,
+    D3D12_TEXTURE_ADDRESS_MODE_BORDER = 4,
+    D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE = 5
+} D3D12_TEXTURE_ADDRESS_MODE;
+typedef enum D3D12_COMPARISON_FUNC {
+    D3D12_COMPARISON_FUNC_NEVER = 1,
+    D3D12_COMPARISON_FUNC_LESS = 2,
+    D3D12_COMPARISON_FUNC_EQUAL = 3,
+    D3D12_COMPARISON_FUNC_LESS_EQUAL = 4,
+    D3D12_COMPARISON_FUNC_GREATER = 5,
+    D3D12_COMPARISON_FUNC_NOT_EQUAL = 6,
+    D3D12_COMPARISON_FUNC_GREATER_EQUAL = 7,
+    D3D12_COMPARISON_FUNC_ALWAYS = 8
+} D3D12_COMPARISON_FUNC;
+typedef struct D3D12_STATIC_SAMPLER_DESC {
+    D3D12_FILTER Filter;
+    D3D12_TEXTURE_ADDRESS_MODE AddressU;
+    D3D12_TEXTURE_ADDRESS_MODE AddressV;
+    D3D12_TEXTURE_ADDRESS_MODE AddressW;
+    FLOAT MipLODBias;
+    UINT MaxAnisotropy;
+    D3D12_COMPARISON_FUNC ComparisonFunc;
+    D3D12_STATIC_BORDER_COLOR BorderColor;
+    FLOAT MinLOD;
+    FLOAT MaxLOD;
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_STATIC_SAMPLER_DESC;
+typedef enum D3D12_ROOT_SIGNATURE_FLAGS {
+    D3D12_ROOT_SIGNATURE_FLAG_NONE = 0x0,
+    D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x1,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS = 0x2,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS = 0x4,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x8,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20,
+    D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT = 0x40
+} D3D12_ROOT_SIGNATURE_FLAGS;
+typedef struct D3D12_ROOT_SIGNATURE_DESC {
+    UINT NumParameters;
+    const D3D12_ROOT_PARAMETER *pParameters;
+    UINT NumStaticSamplers;
+    const D3D12_STATIC_SAMPLER_DESC *pStaticSamplers;
+    D3D12_ROOT_SIGNATURE_FLAGS Flags;
+} D3D12_ROOT_SIGNATURE_DESC;
+typedef struct D3D12_ROOT_SIGNATURE_DESC1 {
+    UINT NumParameters;
+    const D3D12_ROOT_PARAMETER1 *pParameters;
+    UINT NumStaticSamplers;
+    const D3D12_STATIC_SAMPLER_DESC *pStaticSamplers;
+    D3D12_ROOT_SIGNATURE_FLAGS Flags;
+} D3D12_ROOT_SIGNATURE_DESC1;
+typedef enum D3D_ROOT_SIGNATURE_VERSION {
+    D3D_ROOT_SIGNATURE_VERSION_1 = 0x1,
+    D3D_ROOT_SIGNATURE_VERSION_1_0 = 0x1,
+    D3D_ROOT_SIGNATURE_VERSION_1_1 = 0x2
+} D3D_ROOT_SIGNATURE_VERSION;
+typedef struct D3D12_VERSIONED_ROOT_SIGNATURE_DESC {
+    D3D_ROOT_SIGNATURE_VERSION Version;
+    __C89_NAMELESS union {
+        D3D12_ROOT_SIGNATURE_DESC Desc_1_0;
+        D3D12_ROOT_SIGNATURE_DESC1 Desc_1_1;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_VERSIONED_ROOT_SIGNATURE_DESC;
+typedef enum D3D12_DESCRIPTOR_HEAP_TYPE {
+    D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV = 0,
+    D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER = 1,
+    D3D12_DESCRIPTOR_HEAP_TYPE_RTV = 2,
+    D3D12_DESCRIPTOR_HEAP_TYPE_DSV = 3,
+    D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES = 4
+} D3D12_DESCRIPTOR_HEAP_TYPE;
+typedef enum D3D12_DESCRIPTOR_HEAP_FLAGS {
+    D3D12_DESCRIPTOR_HEAP_FLAG_NONE = 0x0,
+    D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE = 0x1
+} D3D12_DESCRIPTOR_HEAP_FLAGS;
+typedef struct D3D12_DESCRIPTOR_HEAP_DESC {
+    D3D12_DESCRIPTOR_HEAP_TYPE Type;
+    UINT NumDescriptors;
+    D3D12_DESCRIPTOR_HEAP_FLAGS Flags;
+    UINT NodeMask;
+} D3D12_DESCRIPTOR_HEAP_DESC;
+typedef UINT64 D3D12_GPU_VIRTUAL_ADDRESS;
+typedef struct D3D12_CONSTANT_BUFFER_VIEW_DESC {
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+} D3D12_CONSTANT_BUFFER_VIEW_DESC;
+typedef enum D3D12_SRV_DIMENSION {
+    D3D12_SRV_DIMENSION_UNKNOWN = 0,
+    D3D12_SRV_DIMENSION_BUFFER = 1,
+    D3D12_SRV_DIMENSION_TEXTURE1D = 2,
+    D3D12_SRV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_SRV_DIMENSION_TEXTURE2D = 4,
+    D3D12_SRV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_SRV_DIMENSION_TEXTURE2DMS = 6,
+    D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
+    D3D12_SRV_DIMENSION_TEXTURE3D = 8,
+    D3D12_SRV_DIMENSION_TEXTURECUBE = 9,
+    D3D12_SRV_DIMENSION_TEXTURECUBEARRAY = 10
+} D3D12_SRV_DIMENSION;
+typedef enum D3D12_BUFFER_SRV_FLAGS {
+    D3D12_BUFFER_SRV_FLAG_NONE = 0x0,
+    D3D12_BUFFER_SRV_FLAG_RAW = 0x1
+} D3D12_BUFFER_SRV_FLAGS;
+typedef enum D3D12_SHADER_COMPONENT_MAPPING {
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 = 0,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1 = 1,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2 = 2,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3 = 3,
+    D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0 = 4,
+    D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1 = 5
+} D3D12_SHADER_COMPONENT_MAPPING;
+#define D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(x, y, z, w) \
+        (((x) & D3D12_SHADER_COMPONENT_MAPPING_MASK) \
+        | (((y) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << D3D12_SHADER_COMPONENT_MAPPING_SHIFT) \
+        | (((z) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 2)) \
+        | (((w) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 3)) \
+        | D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES)
+#define D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, 3)
+#define D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(i, mapping) \
+        ((D3D12_SHADER_COMPONENT_MAPPING)(mapping >> (i * D3D12_SHADER_COMPONENT_MAPPING_SHIFT) \
+        & D3D12_SHADER_COMPONENT_MAPPING_MASK))
+typedef struct D3D12_BUFFER_SRV {
+    UINT64 FirstElement;
+    UINT NumElements;
+    UINT StructureByteStride;
+    D3D12_BUFFER_SRV_FLAGS Flags;
+} D3D12_BUFFER_SRV;
+typedef struct D3D12_TEX1D_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX1D_SRV;
+typedef struct D3D12_TEX1D_ARRAY_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX1D_ARRAY_SRV;
+typedef struct D3D12_TEX2D_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT PlaneSlice;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX2D_SRV;
+typedef struct D3D12_TEX2D_ARRAY_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX2D_ARRAY_SRV;
+typedef struct D3D12_TEX2DMS_SRV {
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_SRV;
+typedef struct D3D12_TEX2DMS_ARRAY_SRV {
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_SRV;
+typedef struct D3D12_TEX3D_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX3D_SRV;
+typedef struct D3D12_TEXCUBE_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEXCUBE_SRV;
+typedef struct D3D12_TEXCUBE_ARRAY_SRV {
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT First2DArrayFace;
+    UINT NumCubes;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEXCUBE_ARRAY_SRV;
+typedef struct D3D12_SHADER_RESOURCE_VIEW_DESC {
+    DXGI_FORMAT Format;
+    D3D12_SRV_DIMENSION ViewDimension;
+    UINT Shader4ComponentMapping;
+    __C89_NAMELESS union {
+        D3D12_BUFFER_SRV Buffer;
+        D3D12_TEX1D_SRV Texture1D;
+        D3D12_TEX1D_ARRAY_SRV Texture1DArray;
+        D3D12_TEX2D_SRV Texture2D;
+        D3D12_TEX2D_ARRAY_SRV Texture2DArray;
+        D3D12_TEX2DMS_SRV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_SRV Texture2DMSArray;
+        D3D12_TEX3D_SRV Texture3D;
+        D3D12_TEXCUBE_SRV TextureCube;
+        D3D12_TEXCUBE_ARRAY_SRV TextureCubeArray;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_SHADER_RESOURCE_VIEW_DESC;
+typedef enum D3D12_UAV_DIMENSION {
+    D3D12_UAV_DIMENSION_UNKNOWN = 0,
+    D3D12_UAV_DIMENSION_BUFFER = 1,
+    D3D12_UAV_DIMENSION_TEXTURE1D = 2,
+    D3D12_UAV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_UAV_DIMENSION_TEXTURE2D = 4,
+    D3D12_UAV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_UAV_DIMENSION_TEXTURE3D = 8
+} D3D12_UAV_DIMENSION;
+typedef enum D3D12_BUFFER_UAV_FLAGS {
+    D3D12_BUFFER_UAV_FLAG_NONE = 0x0,
+    D3D12_BUFFER_UAV_FLAG_RAW = 0x1
+} D3D12_BUFFER_UAV_FLAGS;
+typedef struct D3D12_BUFFER_UAV {
+    UINT64 FirstElement;
+    UINT NumElements;
+    UINT StructureByteStride;
+    UINT64 CounterOffsetInBytes;
+    D3D12_BUFFER_UAV_FLAGS Flags;
+} D3D12_BUFFER_UAV;
+typedef struct D3D12_TEX1D_UAV {
+    UINT MipSlice;
+} D3D12_TEX1D_UAV;
+typedef struct D3D12_TEX1D_ARRAY_UAV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_UAV;
+typedef struct D3D12_TEX2D_UAV {
+    UINT MipSlice;
+    UINT PlaneSlice;
+} D3D12_TEX2D_UAV;
+typedef struct D3D12_TEX2D_ARRAY_UAV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+} D3D12_TEX2D_ARRAY_UAV;
+typedef struct D3D12_TEX3D_UAV {
+    UINT MipSlice;
+    UINT FirstWSlice;
+    UINT WSize;
+} D3D12_TEX3D_UAV;
+typedef struct D3D12_UNORDERED_ACCESS_VIEW_DESC {
+    DXGI_FORMAT Format;
+    D3D12_UAV_DIMENSION ViewDimension;
+    __C89_NAMELESS union {
+        D3D12_BUFFER_UAV Buffer;
+        D3D12_TEX1D_UAV Texture1D;
+        D3D12_TEX1D_ARRAY_UAV Texture1DArray;
+        D3D12_TEX2D_UAV Texture2D;
+        D3D12_TEX2D_ARRAY_UAV Texture2DArray;
+        D3D12_TEX3D_UAV Texture3D;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_UNORDERED_ACCESS_VIEW_DESC;
+typedef enum D3D12_RTV_DIMENSION {
+    D3D12_RTV_DIMENSION_UNKNOWN = 0,
+    D3D12_RTV_DIMENSION_BUFFER = 1,
+    D3D12_RTV_DIMENSION_TEXTURE1D = 2,
+    D3D12_RTV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_RTV_DIMENSION_TEXTURE2D = 4,
+    D3D12_RTV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_RTV_DIMENSION_TEXTURE2DMS = 6,
+    D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY = 7,
+    D3D12_RTV_DIMENSION_TEXTURE3D = 8
+} D3D12_RTV_DIMENSION;
+typedef struct D3D12_BUFFER_RTV {
+    UINT64 FirstElement;
+    UINT NumElements;
+} D3D12_BUFFER_RTV;
+typedef struct D3D12_TEX1D_RTV {
+    UINT MipSlice;
+} D3D12_TEX1D_RTV;
+typedef struct D3D12_TEX1D_ARRAY_RTV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_RTV;
+typedef struct D3D12_TEX2D_RTV {
+    UINT MipSlice;
+    UINT PlaneSlice;
+} D3D12_TEX2D_RTV;
+typedef struct D3D12_TEX2D_ARRAY_RTV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+} D3D12_TEX2D_ARRAY_RTV;
+typedef struct D3D12_TEX2DMS_RTV {
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_RTV;
+typedef struct D3D12_TEX2DMS_ARRAY_RTV {
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_RTV;
+typedef struct D3D12_TEX3D_RTV {
+    UINT MipSlice;
+    UINT FirstWSlice;
+    UINT WSize;
+} D3D12_TEX3D_RTV;
+typedef struct D3D12_RENDER_TARGET_VIEW_DESC {
+    DXGI_FORMAT Format;
+    D3D12_RTV_DIMENSION ViewDimension;
+    __C89_NAMELESS union {
+        D3D12_BUFFER_RTV Buffer;
+        D3D12_TEX1D_RTV Texture1D;
+        D3D12_TEX1D_ARRAY_RTV Texture1DArray;
+        D3D12_TEX2D_RTV Texture2D;
+        D3D12_TEX2D_ARRAY_RTV Texture2DArray;
+        D3D12_TEX2DMS_RTV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_RTV Texture2DMSArray;
+        D3D12_TEX3D_RTV Texture3D;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_RENDER_TARGET_VIEW_DESC;
+typedef enum D3D12_DSV_DIMENSION {
+    D3D12_DSV_DIMENSION_UNKNOWN = 0,
+    D3D12_DSV_DIMENSION_TEXTURE1D = 1,
+    D3D12_DSV_DIMENSION_TEXTURE1DARRAY = 2,
+    D3D12_DSV_DIMENSION_TEXTURE2D = 3,
+    D3D12_DSV_DIMENSION_TEXTURE2DARRAY = 4,
+    D3D12_DSV_DIMENSION_TEXTURE2DMS = 5,
+    D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY = 6
+} D3D12_DSV_DIMENSION;
+typedef enum D3D12_DSV_FLAGS {
+    D3D12_DSV_FLAG_NONE = 0x0,
+    D3D12_DSV_FLAG_READ_ONLY_DEPTH = 0x1,
+    D3D12_DSV_FLAG_READ_ONLY_STENCIL = 0x2
+} D3D12_DSV_FLAGS;
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_DSV_FLAGS);
+typedef struct D3D12_TEX1D_DSV {
+    UINT MipSlice;
+} D3D12_TEX1D_DSV;
+typedef struct D3D12_TEX1D_ARRAY_DSV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_DSV;
+typedef struct D3D12_TEX2D_DSV {
+    UINT MipSlice;
+} D3D12_TEX2D_DSV;
+typedef struct D3D12_TEX2D_ARRAY_DSV {
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2D_ARRAY_DSV;
+typedef struct D3D12_TEX2DMS_DSV {
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_DSV;
+typedef struct D3D12_TEX2DMS_ARRAY_DSV {
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_DSV;
+typedef struct D3D12_DEPTH_STENCIL_VIEW_DESC {
+    DXGI_FORMAT Format;
+    D3D12_DSV_DIMENSION ViewDimension;
+    D3D12_DSV_FLAGS Flags;
+    __C89_NAMELESS union {
+        D3D12_TEX1D_DSV Texture1D;
+        D3D12_TEX1D_ARRAY_DSV Texture1DArray;
+        D3D12_TEX2D_DSV Texture2D;
+        D3D12_TEX2D_ARRAY_DSV Texture2DArray;
+        D3D12_TEX2DMS_DSV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_DSV Texture2DMSArray;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_DEPTH_STENCIL_VIEW_DESC;
+typedef struct D3D12_SAMPLER_DESC {
+    D3D12_FILTER Filter;
+    D3D12_TEXTURE_ADDRESS_MODE AddressU;
+    D3D12_TEXTURE_ADDRESS_MODE AddressV;
+    D3D12_TEXTURE_ADDRESS_MODE AddressW;
+    FLOAT MipLODBias;
+    UINT MaxAnisotropy;
+    D3D12_COMPARISON_FUNC ComparisonFunc;
+    FLOAT BorderColor[4];
+    FLOAT MinLOD;
+    FLOAT MaxLOD;
+} D3D12_SAMPLER_DESC;
+typedef struct D3D12_CPU_DESCRIPTOR_HANDLE {
+    SIZE_T ptr;
+} D3D12_CPU_DESCRIPTOR_HANDLE;
+typedef struct D3D12_GPU_DESCRIPTOR_HANDLE {
+    UINT64 ptr;
+} D3D12_GPU_DESCRIPTOR_HANDLE;
+typedef enum D3D12_STENCIL_OP {
+    D3D12_STENCIL_OP_KEEP = 1,
+    D3D12_STENCIL_OP_ZERO = 2,
+    D3D12_STENCIL_OP_REPLACE = 3,
+    D3D12_STENCIL_OP_INCR_SAT = 4,
+    D3D12_STENCIL_OP_DECR_SAT = 5,
+    D3D12_STENCIL_OP_INVERT = 6,
+    D3D12_STENCIL_OP_INCR = 7,
+    D3D12_STENCIL_OP_DECR = 8
+} D3D12_STENCIL_OP;
+typedef struct D3D12_DEPTH_STENCILOP_DESC {
+    D3D12_STENCIL_OP StencilFailOp;
+    D3D12_STENCIL_OP StencilDepthFailOp;
+    D3D12_STENCIL_OP StencilPassOp;
+    D3D12_COMPARISON_FUNC StencilFunc;
+} D3D12_DEPTH_STENCILOP_DESC;
+typedef enum D3D12_DEPTH_WRITE_MASK {
+    D3D12_DEPTH_WRITE_MASK_ZERO = 0,
+    D3D12_DEPTH_WRITE_MASK_ALL = 1
+} D3D12_DEPTH_WRITE_MASK;
+typedef struct D3D12_DEPTH_STENCIL_DESC {
+    BOOL DepthEnable;
+    D3D12_DEPTH_WRITE_MASK DepthWriteMask;
+    D3D12_COMPARISON_FUNC DepthFunc;
+    BOOL StencilEnable;
+    UINT8 StencilReadMask;
+    UINT8 StencilWriteMask;
+    D3D12_DEPTH_STENCILOP_DESC FrontFace;
+    D3D12_DEPTH_STENCILOP_DESC BackFace;
+} D3D12_DEPTH_STENCIL_DESC;
+typedef enum D3D12_BLEND {
+    D3D12_BLEND_ZERO = 1,
+    D3D12_BLEND_ONE = 2,
+    D3D12_BLEND_SRC_COLOR = 3,
+    D3D12_BLEND_INV_SRC_COLOR = 4,
+    D3D12_BLEND_SRC_ALPHA = 5,
+    D3D12_BLEND_INV_SRC_ALPHA = 6,
+    D3D12_BLEND_DEST_ALPHA = 7,
+    D3D12_BLEND_INV_DEST_ALPHA = 8,
+    D3D12_BLEND_DEST_COLOR = 9,
+    D3D12_BLEND_INV_DEST_COLOR = 10,
+    D3D12_BLEND_SRC_ALPHA_SAT = 11,
+    D3D12_BLEND_BLEND_FACTOR = 14,
+    D3D12_BLEND_INV_BLEND_FACTOR = 15,
+    D3D12_BLEND_SRC1_COLOR = 16,
+    D3D12_BLEND_INV_SRC1_COLOR = 17,
+    D3D12_BLEND_SRC1_ALPHA = 18,
+    D3D12_BLEND_INV_SRC1_ALPHA = 19
+} D3D12_BLEND;
+typedef enum D3D12_BLEND_OP {
+    D3D12_BLEND_OP_ADD = 1,
+    D3D12_BLEND_OP_SUBTRACT = 2,
+    D3D12_BLEND_OP_REV_SUBTRACT = 3,
+    D3D12_BLEND_OP_MIN = 4,
+    D3D12_BLEND_OP_MAX = 5
+} D3D12_BLEND_OP;
+typedef enum D3D12_LOGIC_OP {
+    D3D12_LOGIC_OP_CLEAR = 0,
+    D3D12_LOGIC_OP_SET = 1,
+    D3D12_LOGIC_OP_COPY = 2,
+    D3D12_LOGIC_OP_COPY_INVERTED = 3,
+    D3D12_LOGIC_OP_NOOP = 4
+} D3D12_LOGIC_OP;
+typedef enum D3D12_COLOR_WRITE_ENABLE {
+    D3D12_COLOR_WRITE_ENABLE_RED = 0x1,
+    D3D12_COLOR_WRITE_ENABLE_GREEN = 0x2,
+    D3D12_COLOR_WRITE_ENABLE_BLUE = 0x4,
+    D3D12_COLOR_WRITE_ENABLE_ALPHA = 0x8,
+    D3D12_COLOR_WRITE_ENABLE_ALL = ((D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN) | D3D12_COLOR_WRITE_ENABLE_BLUE) | D3D12_COLOR_WRITE_ENABLE_ALPHA
+} D3D12_COLOR_WRITE_ENABLE;
+typedef struct D3D12_RENDER_TARGET_BLEND_DESC {
+    BOOL BlendEnable;
+    BOOL LogicOpEnable;
+    D3D12_BLEND SrcBlend;
+    D3D12_BLEND DestBlend;
+    D3D12_BLEND_OP BlendOp;
+    D3D12_BLEND SrcBlendAlpha;
+    D3D12_BLEND DestBlendAlpha;
+    D3D12_BLEND_OP BlendOpAlpha;
+    D3D12_LOGIC_OP LogicOp;
+    UINT8 RenderTargetWriteMask;
+} D3D12_RENDER_TARGET_BLEND_DESC;
+typedef struct D3D12_BLEND_DESC {
+    BOOL AlphaToCoverageEnable;
+    BOOL IndependentBlendEnable;
+    D3D12_RENDER_TARGET_BLEND_DESC RenderTarget[8];
+} D3D12_BLEND_DESC;
+typedef enum D3D12_FILL_MODE {
+    D3D12_FILL_MODE_WIREFRAME = 2,
+    D3D12_FILL_MODE_SOLID = 3
+} D3D12_FILL_MODE;
+typedef enum D3D12_CULL_MODE {
+    D3D12_CULL_MODE_NONE = 1,
+    D3D12_CULL_MODE_FRONT = 2,
+    D3D12_CULL_MODE_BACK = 3
+} D3D12_CULL_MODE;
+typedef enum D3D12_CONSERVATIVE_RASTERIZATION_MODE {
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF = 0,
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON = 1
+} D3D12_CONSERVATIVE_RASTERIZATION_MODE;
+typedef struct D3D12_RASTERIZER_DESC {
+    D3D12_FILL_MODE FillMode;
+    D3D12_CULL_MODE CullMode;
+    BOOL FrontCounterClockwise;
+    INT DepthBias;
+    FLOAT DepthBiasClamp;
+    FLOAT SlopeScaledDepthBias;
+    BOOL DepthClipEnable;
+    BOOL MultisampleEnable;
+    BOOL AntialiasedLineEnable;
+    UINT ForcedSampleCount;
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;
+} D3D12_RASTERIZER_DESC;
+typedef struct D3D12_SO_DECLARATION_ENTRY {
+    UINT Stream;
+    const char *SemanticName;
+    UINT SemanticIndex;
+    BYTE StartComponent;
+    BYTE ComponentCount;
+    BYTE OutputSlot;
+} D3D12_SO_DECLARATION_ENTRY;
+typedef struct D3D12_STREAM_OUTPUT_DESC {
+    const D3D12_SO_DECLARATION_ENTRY *pSODeclaration;
+    UINT NumEntries;
+    const UINT *pBufferStrides;
+    UINT NumStrides;
+    UINT RasterizedStream;
+} D3D12_STREAM_OUTPUT_DESC;
+typedef enum D3D12_INPUT_CLASSIFICATION {
+    D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA = 0,
+    D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA = 1
+} D3D12_INPUT_CLASSIFICATION;
+typedef struct D3D12_INPUT_ELEMENT_DESC {
+    const char *SemanticName;
+    UINT SemanticIndex;
+    DXGI_FORMAT Format;
+    UINT InputSlot;
+    UINT AlignedByteOffset;
+    D3D12_INPUT_CLASSIFICATION InputSlotClass;
+    UINT InstanceDataStepRate;
+} D3D12_INPUT_ELEMENT_DESC;
+typedef struct D3D12_INPUT_LAYOUT_DESC {
+    const D3D12_INPUT_ELEMENT_DESC *pInputElementDescs;
+    UINT NumElements;
+} D3D12_INPUT_LAYOUT_DESC;
+typedef enum D3D12_INDEX_BUFFER_STRIP_CUT_VALUE {
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED = 0,
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF = 1,
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF = 2
+} D3D12_INDEX_BUFFER_STRIP_CUT_VALUE;
+typedef D3D_PRIMITIVE_TOPOLOGY D3D12_PRIMITIVE_TOPOLOGY;
+typedef enum D3D12_PRIMITIVE_TOPOLOGY_TYPE {
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED = 0,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT = 1,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE = 2,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE = 3,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH = 4
+} D3D12_PRIMITIVE_TOPOLOGY_TYPE;
+typedef struct D3D12_CACHED_PIPELINE_STATE {
+    const void *pCachedBlob;
+    SIZE_T CachedBlobSizeInBytes;
+} D3D12_CACHED_PIPELINE_STATE;
+typedef enum D3D12_PIPELINE_STATE_FLAGS {
+    D3D12_PIPELINE_STATE_FLAG_NONE = 0x0,
+    D3D12_PIPELINE_STATE_FLAG_DEBUG = 0x1
+} D3D12_PIPELINE_STATE_FLAGS;
+typedef struct D3D12_GRAPHICS_PIPELINE_STATE_DESC {
+    ID3D12RootSignature *pRootSignature;
+    D3D12_SHADER_BYTECODE VS;
+    D3D12_SHADER_BYTECODE PS;
+    D3D12_SHADER_BYTECODE DS;
+    D3D12_SHADER_BYTECODE HS;
+    D3D12_SHADER_BYTECODE GS;
+    D3D12_STREAM_OUTPUT_DESC StreamOutput;
+    D3D12_BLEND_DESC BlendState;
+    UINT SampleMask;
+    D3D12_RASTERIZER_DESC RasterizerState;
+    D3D12_DEPTH_STENCIL_DESC DepthStencilState;
+    D3D12_INPUT_LAYOUT_DESC InputLayout;
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;
+    UINT NumRenderTargets;
+    DXGI_FORMAT RTVFormats[8];
+    DXGI_FORMAT DSVFormat;
+    DXGI_SAMPLE_DESC SampleDesc;
+    UINT NodeMask;
+    D3D12_CACHED_PIPELINE_STATE CachedPSO;
+    D3D12_PIPELINE_STATE_FLAGS Flags;
+} D3D12_GRAPHICS_PIPELINE_STATE_DESC;
+typedef struct D3D12_COMPUTE_PIPELINE_STATE_DESC {
+    ID3D12RootSignature *pRootSignature;
+    D3D12_SHADER_BYTECODE CS;
+    UINT NodeMask;
+    D3D12_CACHED_PIPELINE_STATE CachedPSO;
+    D3D12_PIPELINE_STATE_FLAGS Flags;
+} D3D12_COMPUTE_PIPELINE_STATE_DESC;
+typedef enum D3D12_COMMAND_LIST_TYPE {
+    D3D12_COMMAND_LIST_TYPE_DIRECT = 0,
+    D3D12_COMMAND_LIST_TYPE_BUNDLE = 1,
+    D3D12_COMMAND_LIST_TYPE_COMPUTE = 2,
+    D3D12_COMMAND_LIST_TYPE_COPY = 3
+} D3D12_COMMAND_LIST_TYPE;
+typedef enum D3D12_COMMAND_QUEUE_PRIORITY {
+    D3D12_COMMAND_QUEUE_PRIORITY_NORMAL = 0,
+    D3D12_COMMAND_QUEUE_PRIORITY_HIGH = 100,
+    D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME = 10000
+} D3D12_COMMAND_QUEUE_PRIORITY;
+typedef enum D3D12_COMMAND_QUEUE_FLAGS {
+    D3D12_COMMAND_QUEUE_FLAG_NONE = 0x0,
+    D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT = 0x1
+} D3D12_COMMAND_QUEUE_FLAGS;
+typedef struct D3D12_COMMAND_QUEUE_DESC {
+    D3D12_COMMAND_LIST_TYPE Type;
+    INT Priority;
+    D3D12_COMMAND_QUEUE_FLAGS Flags;
+    UINT NodeMask;
+} D3D12_COMMAND_QUEUE_DESC;
+typedef struct D3D12_FEATURE_DATA_ARCHITECTURE {
+    UINT NodeIndex;
+    BOOL TileBasedRenderer;
+    BOOL UMA;
+    BOOL CacheCoherentUMA;
+} D3D12_FEATURE_DATA_ARCHITECTURE;
+typedef struct D3D12_FEATURE_DATA_FORMAT_INFO {
+    DXGI_FORMAT Format;
+    UINT8 PlaneCount;
+} D3D12_FEATURE_DATA_FORMAT_INFO;
+typedef struct D3D12_FEATURE_DATA_FEATURE_LEVELS {
+    UINT NumFeatureLevels;
+    const D3D_FEATURE_LEVEL *pFeatureLevelsRequested;
+    D3D_FEATURE_LEVEL MaxSupportedFeatureLevel;
+} D3D12_FEATURE_DATA_FEATURE_LEVELS;
+typedef struct D3D12_FEATURE_DATA_ROOT_SIGNATURE {
+    D3D_ROOT_SIGNATURE_VERSION HighestVersion;
+} D3D12_FEATURE_DATA_ROOT_SIGNATURE;
+typedef struct D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT {
+    UINT MaxGPUVirtualAddressBitsPerResource;
+    UINT MaxGPUVirtualAddressBitsPerProcess;
+} D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT;
+typedef enum D3D_SHADER_MODEL {
+    D3D_SHADER_MODEL_5_1 = 0x51,
+    D3D_SHADER_MODEL_6_0 = 0x60
+} D3D_SHADER_MODEL;
+typedef struct D3D12_FEATURE_DATA_SHADER_MODEL {
+    D3D_SHADER_MODEL HighestShaderModel;
+} D3D12_FEATURE_DATA_SHADER_MODEL;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS1 {
+    BOOL WaveOps;
+    UINT WaveLaneCountMin;
+    UINT WaveLaneCountMax;
+    UINT TotalLaneCount;
+    BOOL ExpandedComputeResourceStates;
+    BOOL Int64ShaderOps;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS1;
+typedef struct D3D12_FEATURE_DATA_ARCHITECTURE1 {
+    UINT NodeIndex;
+    BOOL TileBasedRenderer;
+    BOOL UMA;
+    BOOL CacheCoherentUMA;
+    BOOL IsolatedMMU;
+} D3D12_FEATURE_DATA_ARCHITECTURE1;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS2 {
+    BOOL DepthBoundsTestSupported;
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER ProgrammableSamplePositionsTier;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS2;
+typedef struct D3D12_FEATURE_DATA_SHADER_CACHE {
+    D3D12_SHADER_CACHE_SUPPORT_FLAGS SupportFlags;
+} D3D12_FEATURE_DATA_SHADER_CACHE;
+typedef struct D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY {
+    D3D12_COMMAND_LIST_TYPE CommandListType;
+    UINT Priority;
+    BOOL PriorityForTypeIsSupported;
+} D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS3 {
+    BOOL CopyQueueTimestampQueriesSupported;
+    BOOL CastingFullyTypedFormatSupported;
+    D3D12_COMMAND_LIST_SUPPORT_FLAGS WriteBufferImmediateSupportFlags;
+    D3D12_VIEW_INSTANCING_TIER ViewInstancingTier;
+    BOOL BarycentricsSupported;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS3;
+typedef struct D3D12_FEATURE_DATA_EXISTING_HEAPS {
+    BOOL Supported;
+} D3D12_FEATURE_DATA_EXISTING_HEAPS;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS4 {
+    BOOL MSAA64KBAlignedTextureSupported;
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER SharedResourceCompatibilityTier;
+    BOOL Native16BitShaderOpsSupported;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS4;
+typedef struct D3D12_FEATURE_DATA_SERIALIZATION {
+    UINT NodeIndex;
+    D3D12_HEAP_SERIALIZATION_TIER HeapSerializationTier;
+} D3D12_FEATURE_DATA_SERIALIZATION;
+typedef struct D3D12_FEATURE_DATA_CROSS_NODE {
+    D3D12_CROSS_NODE_SHARING_TIER SharingTier;
+    BOOL AtomicShaderInstructions;
+} D3D12_FEATURE_DATA_CROSS_NODE;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS5 {
+    BOOL SRVOnlyTiledResourceTier3;
+    D3D12_RENDER_PASS_TIER RenderPassesTier;
+    D3D12_RAYTRACING_TIER RaytracingTier;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS5;
+typedef enum D3D12_FEATURE {
+    D3D12_FEATURE_D3D12_OPTIONS = 0,
+    D3D12_FEATURE_ARCHITECTURE = 1,
+    D3D12_FEATURE_FEATURE_LEVELS = 2,
+    D3D12_FEATURE_FORMAT_SUPPORT = 3,
+    D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS = 4,
+    D3D12_FEATURE_FORMAT_INFO = 5,
+    D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT = 6,
+    D3D12_FEATURE_SHADER_MODEL = 7,
+    D3D12_FEATURE_D3D12_OPTIONS1 = 8,
+    D3D12_FEATURE_ROOT_SIGNATURE = 12,
+    D3D12_FEATURE_ARCHITECTURE1 = 16,
+    D3D12_FEATURE_D3D12_OPTIONS2 = 18,
+    D3D12_FEATURE_SHADER_CACHE = 19,
+    D3D12_FEATURE_COMMAND_QUEUE_PRIORITY = 20,
+    D3D12_FEATURE_D3D12_OPTIONS3 = 21,
+    D3D12_FEATURE_EXISTING_HEAPS = 22,
+    D3D12_FEATURE_D3D12_OPTIONS4 = 23,
+    D3D12_FEATURE_SERIALIZATION = 24,
+    D3D12_FEATURE_CROSS_NODE = 25,
+    D3D12_FEATURE_D3D12_OPTIONS5 = 27
+} D3D12_FEATURE;
+typedef struct D3D12_MEMCPY_DEST {
+    void *pData;
+    SIZE_T RowPitch;
+    SIZE_T SlicePitch;
+} D3D12_MEMCPY_DEST;
+typedef struct D3D12_SUBRESOURCE_DATA {
+    const void *pData;
+    LONG_PTR RowPitch;
+    LONG_PTR SlicePitch;
+} D3D12_SUBRESOURCE_DATA;
+typedef enum D3D12_MULTIPLE_FENCE_WAIT_FLAGS {
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_NONE = 0x0,
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY = 0x1,
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL = 0x0
+} D3D12_MULTIPLE_FENCE_WAIT_FLAGS;
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_MULTIPLE_FENCE_WAIT_FLAGS);
+typedef enum D3D12_RESIDENCY_PRIORITY {
+    D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000,
+    D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000,
+    D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000,
+    D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000,
+    D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000
+} D3D12_RESIDENCY_PRIORITY;
+typedef struct D3D12_WRITEBUFFERIMMEDIATE_PARAMETER {
+    D3D12_GPU_VIRTUAL_ADDRESS Dest;
+    UINT32 Value;
+} D3D12_WRITEBUFFERIMMEDIATE_PARAMETER;
+/*****************************************************************************
+ * ID3D12Object interface
+ */
+#ifndef __ID3D12Object_INTERFACE_DEFINED__
+#define __ID3D12Object_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Object, 0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("c4fec28f-7966-4e95-9f94-f431cb56c3b8")
+ID3D12Object : public IUnknown
+{
+    virtual HRESULT STDMETHODCALLTYPE GetPrivateData(
+        REFGUID guid,
+        UINT *data_size,
+        void *data) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetPrivateData(
+        REFGUID guid,
+        UINT data_size,
+        const void *data) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+        REFGUID guid,
+        const IUnknown *data) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetName(
+        const WCHAR *name) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Object, 0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8)
+#endif
+#else
+typedef struct ID3D12ObjectVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Object *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Object *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Object *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Object *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Object *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Object *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Object *This,
+        const WCHAR *name);
+
+    END_INTERFACE
+} ID3D12ObjectVtbl;
+
+interface ID3D12Object {
+    CONST_VTBL ID3D12ObjectVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Object_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Object_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Object_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Object_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Object_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Object_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Object_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Object_QueryInterface(ID3D12Object* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Object_AddRef(ID3D12Object* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Object_Release(ID3D12Object* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Object_GetPrivateData(ID3D12Object* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Object_SetPrivateData(ID3D12Object* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Object_SetPrivateDataInterface(ID3D12Object* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Object_SetName(ID3D12Object* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Object_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12DeviceChild interface
+ */
+#ifndef __ID3D12DeviceChild_INTERFACE_DEFINED__
+#define __ID3D12DeviceChild_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12DeviceChild, 0x905db94b, 0xa00c, 0x4140, 0x9d,0xf5, 0x2b,0x64,0xca,0x9e,0xa3,0x57);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("905db94b-a00c-4140-9df5-2b64ca9ea357")
+ID3D12DeviceChild : public ID3D12Object
+{
+    virtual HRESULT STDMETHODCALLTYPE GetDevice(
+        REFIID riid,
+        void **device) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12DeviceChild, 0x905db94b, 0xa00c, 0x4140, 0x9d,0xf5, 0x2b,0x64,0xca,0x9e,0xa3,0x57)
+#endif
+#else
+typedef struct ID3D12DeviceChildVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12DeviceChild *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12DeviceChild *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12DeviceChild *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12DeviceChild *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12DeviceChild *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12DeviceChild *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12DeviceChild *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12DeviceChild *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} ID3D12DeviceChildVtbl;
+
+interface ID3D12DeviceChild {
+    CONST_VTBL ID3D12DeviceChildVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12DeviceChild_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12DeviceChild_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12DeviceChild_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12DeviceChild_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12DeviceChild_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12DeviceChild_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12DeviceChild_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12DeviceChild_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12DeviceChild_QueryInterface(ID3D12DeviceChild* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12DeviceChild_AddRef(ID3D12DeviceChild* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12DeviceChild_Release(ID3D12DeviceChild* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12DeviceChild_GetPrivateData(ID3D12DeviceChild* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12DeviceChild_SetPrivateData(ID3D12DeviceChild* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12DeviceChild_SetPrivateDataInterface(ID3D12DeviceChild* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12DeviceChild_SetName(ID3D12DeviceChild* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12DeviceChild_GetDevice(ID3D12DeviceChild* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12DeviceChild_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Pageable interface
+ */
+#ifndef __ID3D12Pageable_INTERFACE_DEFINED__
+#define __ID3D12Pageable_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Pageable, 0x63ee58fb, 0x1268, 0x4835, 0x86,0xda, 0xf0,0x08,0xce,0x62,0xf0,0xd6);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("63ee58fb-1268-4835-86da-f008ce62f0d6")
+ID3D12Pageable : public ID3D12DeviceChild
+{
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Pageable, 0x63ee58fb, 0x1268, 0x4835, 0x86,0xda, 0xf0,0x08,0xce,0x62,0xf0,0xd6)
+#endif
+#else
+typedef struct ID3D12PageableVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Pageable *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Pageable *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Pageable *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Pageable *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Pageable *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Pageable *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Pageable *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12Pageable *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} ID3D12PageableVtbl;
+
+interface ID3D12Pageable {
+    CONST_VTBL ID3D12PageableVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Pageable_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Pageable_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Pageable_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Pageable_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Pageable_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Pageable_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Pageable_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12Pageable_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Pageable_QueryInterface(ID3D12Pageable* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Pageable_AddRef(ID3D12Pageable* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Pageable_Release(ID3D12Pageable* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Pageable_GetPrivateData(ID3D12Pageable* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Pageable_SetPrivateData(ID3D12Pageable* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Pageable_SetPrivateDataInterface(ID3D12Pageable* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Pageable_SetName(ID3D12Pageable* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12Pageable_GetDevice(ID3D12Pageable* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Pageable_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Heap interface
+ */
+#ifndef __ID3D12Heap_INTERFACE_DEFINED__
+#define __ID3D12Heap_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Heap, 0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("6b3b2502-6e51-45b3-90ee-9884265e8df3")
+ID3D12Heap : public ID3D12Pageable
+{
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_HEAP_DESC* STDMETHODCALLTYPE GetDesc(
+        D3D12_HEAP_DESC *__ret) = 0;
+    D3D12_HEAP_DESC STDMETHODCALLTYPE GetDesc(
+        )
+    {
+        D3D12_HEAP_DESC __ret;
+        return *GetDesc(&__ret);
+    }
+#else
+    virtual D3D12_HEAP_DESC STDMETHODCALLTYPE GetDesc(
+        ) = 0;
+#endif
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Heap, 0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3)
+#endif
+#else
+typedef struct ID3D12HeapVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Heap *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Heap *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Heap *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Heap *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Heap *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Heap *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Heap *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12Heap *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12Heap methods ***/
+    D3D12_HEAP_DESC * (STDMETHODCALLTYPE *GetDesc)(
+        ID3D12Heap *This,
+        D3D12_HEAP_DESC *__ret);
+
+    END_INTERFACE
+} ID3D12HeapVtbl;
+
+interface ID3D12Heap {
+    CONST_VTBL ID3D12HeapVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Heap_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Heap_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Heap_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Heap_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Heap_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Heap_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Heap_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12Heap_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12Heap methods ***/
+#define ID3D12Heap_GetDesc(This) ID3D12Heap_GetDesc_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Heap_QueryInterface(ID3D12Heap* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Heap_AddRef(ID3D12Heap* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Heap_Release(ID3D12Heap* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Heap_GetPrivateData(ID3D12Heap* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Heap_SetPrivateData(ID3D12Heap* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Heap_SetPrivateDataInterface(ID3D12Heap* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Heap_SetName(ID3D12Heap* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12Heap_GetDevice(ID3D12Heap* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12Heap methods ***/
+static FORCEINLINE D3D12_HEAP_DESC ID3D12Heap_GetDesc(ID3D12Heap* This) {
+    D3D12_HEAP_DESC __ret;
+    return *This->lpVtbl->GetDesc(This,&__ret);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Heap_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Resource interface
+ */
+#ifndef __ID3D12Resource_INTERFACE_DEFINED__
+#define __ID3D12Resource_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Resource, 0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("696442be-a72e-4059-bc79-5b5c98040fad")
+ID3D12Resource : public ID3D12Pageable
+{
+    virtual HRESULT STDMETHODCALLTYPE Map(
+        UINT sub_resource,
+        const D3D12_RANGE *read_range,
+        void **data) = 0;
+
+    virtual void STDMETHODCALLTYPE Unmap(
+        UINT sub_resource,
+        const D3D12_RANGE *written_range) = 0;
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_RESOURCE_DESC* STDMETHODCALLTYPE GetDesc(
+        D3D12_RESOURCE_DESC *__ret) = 0;
+    D3D12_RESOURCE_DESC STDMETHODCALLTYPE GetDesc(
+        )
+    {
+        D3D12_RESOURCE_DESC __ret;
+        return *GetDesc(&__ret);
+    }
+#else
+    virtual D3D12_RESOURCE_DESC STDMETHODCALLTYPE GetDesc(
+        ) = 0;
+#endif
+
+    virtual D3D12_GPU_VIRTUAL_ADDRESS STDMETHODCALLTYPE GetGPUVirtualAddress(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE WriteToSubresource(
+        UINT dst_sub_resource,
+        const D3D12_BOX *dst_box,
+        const void *src_data,
+        UINT src_row_pitch,
+        UINT src_slice_pitch) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ReadFromSubresource(
+        void *dst_data,
+        UINT dst_row_pitch,
+        UINT dst_slice_pitch,
+        UINT src_sub_resource,
+        const D3D12_BOX *src_box) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetHeapProperties(
+        D3D12_HEAP_PROPERTIES *heap_properties,
+        D3D12_HEAP_FLAGS *flags) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Resource, 0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad)
+#endif
+#else
+typedef struct ID3D12ResourceVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Resource *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Resource *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Resource *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Resource *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Resource *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Resource *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Resource *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12Resource *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12Resource methods ***/
+    HRESULT (STDMETHODCALLTYPE *Map)(
+        ID3D12Resource *This,
+        UINT sub_resource,
+        const D3D12_RANGE *read_range,
+        void **data);
+
+    void (STDMETHODCALLTYPE *Unmap)(
+        ID3D12Resource *This,
+        UINT sub_resource,
+        const D3D12_RANGE *written_range);
+
+    D3D12_RESOURCE_DESC * (STDMETHODCALLTYPE *GetDesc)(
+        ID3D12Resource *This,
+        D3D12_RESOURCE_DESC *__ret);
+
+    D3D12_GPU_VIRTUAL_ADDRESS (STDMETHODCALLTYPE *GetGPUVirtualAddress)(
+        ID3D12Resource *This);
+
+    HRESULT (STDMETHODCALLTYPE *WriteToSubresource)(
+        ID3D12Resource *This,
+        UINT dst_sub_resource,
+        const D3D12_BOX *dst_box,
+        const void *src_data,
+        UINT src_row_pitch,
+        UINT src_slice_pitch);
+
+    HRESULT (STDMETHODCALLTYPE *ReadFromSubresource)(
+        ID3D12Resource *This,
+        void *dst_data,
+        UINT dst_row_pitch,
+        UINT dst_slice_pitch,
+        UINT src_sub_resource,
+        const D3D12_BOX *src_box);
+
+    HRESULT (STDMETHODCALLTYPE *GetHeapProperties)(
+        ID3D12Resource *This,
+        D3D12_HEAP_PROPERTIES *heap_properties,
+        D3D12_HEAP_FLAGS *flags);
+
+    END_INTERFACE
+} ID3D12ResourceVtbl;
+
+interface ID3D12Resource {
+    CONST_VTBL ID3D12ResourceVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Resource_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Resource_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Resource_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Resource_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Resource_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Resource_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Resource_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12Resource_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12Resource methods ***/
+#define ID3D12Resource_Map(This,sub_resource,read_range,data) (This)->lpVtbl->Map(This,sub_resource,read_range,data)
+#define ID3D12Resource_Unmap(This,sub_resource,written_range) (This)->lpVtbl->Unmap(This,sub_resource,written_range)
+#define ID3D12Resource_GetDesc(This) ID3D12Resource_GetDesc_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12Resource_GetGPUVirtualAddress(This) (This)->lpVtbl->GetGPUVirtualAddress(This)
+#define ID3D12Resource_WriteToSubresource(This,dst_sub_resource,dst_box,src_data,src_row_pitch,src_slice_pitch) (This)->lpVtbl->WriteToSubresource(This,dst_sub_resource,dst_box,src_data,src_row_pitch,src_slice_pitch)
+#define ID3D12Resource_ReadFromSubresource(This,dst_data,dst_row_pitch,dst_slice_pitch,src_sub_resource,src_box) (This)->lpVtbl->ReadFromSubresource(This,dst_data,dst_row_pitch,dst_slice_pitch,src_sub_resource,src_box)
+#define ID3D12Resource_GetHeapProperties(This,heap_properties,flags) (This)->lpVtbl->GetHeapProperties(This,heap_properties,flags)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Resource_QueryInterface(ID3D12Resource* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Resource_AddRef(ID3D12Resource* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Resource_Release(ID3D12Resource* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Resource_GetPrivateData(ID3D12Resource* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Resource_SetPrivateData(ID3D12Resource* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Resource_SetPrivateDataInterface(ID3D12Resource* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Resource_SetName(ID3D12Resource* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12Resource_GetDevice(ID3D12Resource* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12Resource methods ***/
+static FORCEINLINE HRESULT ID3D12Resource_Map(ID3D12Resource* This,UINT sub_resource,const D3D12_RANGE *read_range,void **data) {
+    return This->lpVtbl->Map(This,sub_resource,read_range,data);
+}
+static FORCEINLINE void ID3D12Resource_Unmap(ID3D12Resource* This,UINT sub_resource,const D3D12_RANGE *written_range) {
+    This->lpVtbl->Unmap(This,sub_resource,written_range);
+}
+static FORCEINLINE D3D12_RESOURCE_DESC ID3D12Resource_GetDesc(ID3D12Resource* This) {
+    D3D12_RESOURCE_DESC __ret;
+    return *This->lpVtbl->GetDesc(This,&__ret);
+}
+static FORCEINLINE D3D12_GPU_VIRTUAL_ADDRESS ID3D12Resource_GetGPUVirtualAddress(ID3D12Resource* This) {
+    return This->lpVtbl->GetGPUVirtualAddress(This);
+}
+static FORCEINLINE HRESULT ID3D12Resource_WriteToSubresource(ID3D12Resource* This,UINT dst_sub_resource,const D3D12_BOX *dst_box,const void *src_data,UINT src_row_pitch,UINT src_slice_pitch) {
+    return This->lpVtbl->WriteToSubresource(This,dst_sub_resource,dst_box,src_data,src_row_pitch,src_slice_pitch);
+}
+static FORCEINLINE HRESULT ID3D12Resource_ReadFromSubresource(ID3D12Resource* This,void *dst_data,UINT dst_row_pitch,UINT dst_slice_pitch,UINT src_sub_resource,const D3D12_BOX *src_box) {
+    return This->lpVtbl->ReadFromSubresource(This,dst_data,dst_row_pitch,dst_slice_pitch,src_sub_resource,src_box);
+}
+static FORCEINLINE HRESULT ID3D12Resource_GetHeapProperties(ID3D12Resource* This,D3D12_HEAP_PROPERTIES *heap_properties,D3D12_HEAP_FLAGS *flags) {
+    return This->lpVtbl->GetHeapProperties(This,heap_properties,flags);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Resource_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12CommandList interface
+ */
+#ifndef __ID3D12CommandList_INTERFACE_DEFINED__
+#define __ID3D12CommandList_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12CommandList, 0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("7116d91c-e7e4-47ce-b8c6-ec8168f437e5")
+ID3D12CommandList : public ID3D12DeviceChild
+{
+    virtual D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE GetType(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12CommandList, 0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5)
+#endif
+#else
+typedef struct ID3D12CommandListVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12CommandList *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12CommandList *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12CommandList *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12CommandList *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12CommandList *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12CommandList *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12CommandList *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12CommandList *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandList methods ***/
+    D3D12_COMMAND_LIST_TYPE (STDMETHODCALLTYPE *GetType)(
+        ID3D12CommandList *This);
+
+    END_INTERFACE
+} ID3D12CommandListVtbl;
+
+interface ID3D12CommandList {
+    CONST_VTBL ID3D12CommandListVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12CommandList_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12CommandList_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12CommandList_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12CommandList_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandList_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandList_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12CommandList_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12CommandList_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandList methods ***/
+#define ID3D12CommandList_GetType(This) (This)->lpVtbl->GetType(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12CommandList_QueryInterface(ID3D12CommandList* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12CommandList_AddRef(ID3D12CommandList* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12CommandList_Release(ID3D12CommandList* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12CommandList_GetPrivateData(ID3D12CommandList* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandList_SetPrivateData(ID3D12CommandList* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandList_SetPrivateDataInterface(ID3D12CommandList* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandList_SetName(ID3D12CommandList* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12CommandList_GetDevice(ID3D12CommandList* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandList methods ***/
+static FORCEINLINE D3D12_COMMAND_LIST_TYPE ID3D12CommandList_GetType(ID3D12CommandList* This) {
+    return This->lpVtbl->GetType(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12CommandList_INTERFACE_DEFINED__ */
+
+typedef enum D3D12_TILE_COPY_FLAGS {
+    D3D12_TILE_COPY_FLAG_NONE = 0x0,
+    D3D12_TILE_COPY_FLAG_NO_HAZARD = 0x1,
+    D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE = 0x2,
+    D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER = 0x4
+} D3D12_TILE_COPY_FLAGS;
+typedef struct D3D12_INDEX_BUFFER_VIEW {
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+    DXGI_FORMAT Format;
+} D3D12_INDEX_BUFFER_VIEW;
+typedef struct D3D12_VERTEX_BUFFER_VIEW {
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+    UINT StrideInBytes;
+} D3D12_VERTEX_BUFFER_VIEW;
+typedef struct D3D12_STREAM_OUTPUT_BUFFER_VIEW {
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT64 SizeInBytes;
+    D3D12_GPU_VIRTUAL_ADDRESS BufferFilledSizeLocation;
+} D3D12_STREAM_OUTPUT_BUFFER_VIEW;
+typedef enum D3D12_CLEAR_FLAGS {
+    D3D12_CLEAR_FLAG_DEPTH = 0x1,
+    D3D12_CLEAR_FLAG_STENCIL = 0x2
+} D3D12_CLEAR_FLAGS;
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_CLEAR_FLAGS);
+typedef struct D3D12_DISCARD_REGION {
+    UINT NumRects;
+    const D3D12_RECT *pRects;
+    UINT FirstSubresource;
+    UINT NumSubresources;
+} D3D12_DISCARD_REGION;
+typedef enum D3D12_QUERY_TYPE {
+    D3D12_QUERY_TYPE_OCCLUSION = 0,
+    D3D12_QUERY_TYPE_BINARY_OCCLUSION = 1,
+    D3D12_QUERY_TYPE_TIMESTAMP = 2,
+    D3D12_QUERY_TYPE_PIPELINE_STATISTICS = 3,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 = 4,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM1 = 5,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM2 = 6,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3 = 7
+} D3D12_QUERY_TYPE;
+typedef struct D3D12_QUERY_DATA_PIPELINE_STATISTICS {
+    UINT64 IAVertices;
+    UINT64 IAPrimitives;
+    UINT64 VSInvocations;
+    UINT64 GSInvocations;
+    UINT64 GSPrimitives;
+    UINT64 CInvocations;
+    UINT64 CPrimitives;
+    UINT64 PSInvocations;
+    UINT64 HSInvocations;
+    UINT64 DSInvocations;
+    UINT64 CSInvocations;
+} D3D12_QUERY_DATA_PIPELINE_STATISTICS;
+typedef struct D3D12_QUERY_DATA_SO_STATISTICS {
+    UINT64 NumPrimitivesWritten;
+    UINT64 PrimitivesStorageNeeded;
+} D3D12_QUERY_DATA_SO_STATISTICS;
+typedef enum D3D12_PREDICATION_OP {
+    D3D12_PREDICATION_OP_EQUAL_ZERO = 0,
+    D3D12_PREDICATION_OP_NOT_EQUAL_ZERO = 1
+} D3D12_PREDICATION_OP;
+/*****************************************************************************
+ * ID3D12DescriptorHeap interface
+ */
+#ifndef __ID3D12DescriptorHeap_INTERFACE_DEFINED__
+#define __ID3D12DescriptorHeap_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12DescriptorHeap, 0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("8efb471d-616c-4f49-90f7-127bb763fa51")
+ID3D12DescriptorHeap : public ID3D12Pageable
+{
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_DESCRIPTOR_HEAP_DESC* STDMETHODCALLTYPE GetDesc(
+        D3D12_DESCRIPTOR_HEAP_DESC *__ret) = 0;
+    D3D12_DESCRIPTOR_HEAP_DESC STDMETHODCALLTYPE GetDesc(
+        )
+    {
+        D3D12_DESCRIPTOR_HEAP_DESC __ret;
+        return *GetDesc(&__ret);
+    }
+#else
+    virtual D3D12_DESCRIPTOR_HEAP_DESC STDMETHODCALLTYPE GetDesc(
+        ) = 0;
+#endif
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_CPU_DESCRIPTOR_HANDLE* STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart(
+        D3D12_CPU_DESCRIPTOR_HANDLE *__ret) = 0;
+    D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart(
+        )
+    {
+        D3D12_CPU_DESCRIPTOR_HANDLE __ret;
+        return *GetCPUDescriptorHandleForHeapStart(&__ret);
+    }
+#else
+    virtual D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart(
+        ) = 0;
+#endif
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_GPU_DESCRIPTOR_HANDLE* STDMETHODCALLTYPE GetGPUDescriptorHandleForHeapStart(
+        D3D12_GPU_DESCRIPTOR_HANDLE *__ret) = 0;
+    D3D12_GPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetGPUDescriptorHandleForHeapStart(
+        )
+    {
+        D3D12_GPU_DESCRIPTOR_HANDLE __ret;
+        return *GetGPUDescriptorHandleForHeapStart(&__ret);
+    }
+#else
+    virtual D3D12_GPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetGPUDescriptorHandleForHeapStart(
+        ) = 0;
+#endif
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12DescriptorHeap, 0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51)
+#endif
+#else
+typedef struct ID3D12DescriptorHeapVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12DescriptorHeap *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12DescriptorHeap *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12DescriptorHeap *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12DescriptorHeap *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12DescriptorHeap *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12DescriptorHeap *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12DescriptorHeap *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12DescriptorHeap *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12DescriptorHeap methods ***/
+    D3D12_DESCRIPTOR_HEAP_DESC * (STDMETHODCALLTYPE *GetDesc)(
+        ID3D12DescriptorHeap *This,
+        D3D12_DESCRIPTOR_HEAP_DESC *__ret);
+
+    D3D12_CPU_DESCRIPTOR_HANDLE * (STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart)(
+        ID3D12DescriptorHeap *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE *__ret);
+
+    D3D12_GPU_DESCRIPTOR_HANDLE * (STDMETHODCALLTYPE *GetGPUDescriptorHandleForHeapStart)(
+        ID3D12DescriptorHeap *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE *__ret);
+
+    END_INTERFACE
+} ID3D12DescriptorHeapVtbl;
+
+interface ID3D12DescriptorHeap {
+    CONST_VTBL ID3D12DescriptorHeapVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12DescriptorHeap_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12DescriptorHeap_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12DescriptorHeap_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12DescriptorHeap_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12DescriptorHeap_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12DescriptorHeap_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12DescriptorHeap_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12DescriptorHeap_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12DescriptorHeap methods ***/
+#define ID3D12DescriptorHeap_GetDesc(This) ID3D12DescriptorHeap_GetDesc_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(This) ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(This) ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_QueryInterface(ID3D12DescriptorHeap* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12DescriptorHeap_AddRef(ID3D12DescriptorHeap* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12DescriptorHeap_Release(ID3D12DescriptorHeap* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_GetPrivateData(ID3D12DescriptorHeap* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_SetPrivateData(ID3D12DescriptorHeap* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_SetPrivateDataInterface(ID3D12DescriptorHeap* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_SetName(ID3D12DescriptorHeap* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12DescriptorHeap_GetDevice(ID3D12DescriptorHeap* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12DescriptorHeap methods ***/
+static FORCEINLINE D3D12_DESCRIPTOR_HEAP_DESC ID3D12DescriptorHeap_GetDesc(ID3D12DescriptorHeap* This) {
+    D3D12_DESCRIPTOR_HEAP_DESC __ret;
+    return *This->lpVtbl->GetDesc(This,&__ret);
+}
+static FORCEINLINE D3D12_CPU_DESCRIPTOR_HANDLE ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap* This) {
+    D3D12_CPU_DESCRIPTOR_HANDLE __ret;
+    return *This->lpVtbl->GetCPUDescriptorHandleForHeapStart(This,&__ret);
+}
+static FORCEINLINE D3D12_GPU_DESCRIPTOR_HANDLE ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap* This) {
+    D3D12_GPU_DESCRIPTOR_HANDLE __ret;
+    return *This->lpVtbl->GetGPUDescriptorHandleForHeapStart(This,&__ret);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12DescriptorHeap_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12QueryHeap interface
+ */
+#ifndef __ID3D12QueryHeap_INTERFACE_DEFINED__
+#define __ID3D12QueryHeap_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12QueryHeap, 0x0d9658ae, 0xed45, 0x469e, 0xa6,0x1d, 0x97,0x0e,0xc5,0x83,0xca,0xb4);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("0d9658ae-ed45-469e-a61d-970ec583cab4")
+ID3D12QueryHeap : public ID3D12Pageable
+{
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12QueryHeap, 0x0d9658ae, 0xed45, 0x469e, 0xa6,0x1d, 0x97,0x0e,0xc5,0x83,0xca,0xb4)
+#endif
+#else
+typedef struct ID3D12QueryHeapVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12QueryHeap *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12QueryHeap *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12QueryHeap *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12QueryHeap *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12QueryHeap *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12QueryHeap *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12QueryHeap *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12QueryHeap *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} ID3D12QueryHeapVtbl;
+
+interface ID3D12QueryHeap {
+    CONST_VTBL ID3D12QueryHeapVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12QueryHeap_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12QueryHeap_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12QueryHeap_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12QueryHeap_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12QueryHeap_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12QueryHeap_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12QueryHeap_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12QueryHeap_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12QueryHeap_QueryInterface(ID3D12QueryHeap* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12QueryHeap_AddRef(ID3D12QueryHeap* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12QueryHeap_Release(ID3D12QueryHeap* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12QueryHeap_GetPrivateData(ID3D12QueryHeap* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12QueryHeap_SetPrivateData(ID3D12QueryHeap* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12QueryHeap_SetPrivateDataInterface(ID3D12QueryHeap* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12QueryHeap_SetName(ID3D12QueryHeap* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12QueryHeap_GetDevice(ID3D12QueryHeap* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12QueryHeap_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12CommandSignature interface
+ */
+#ifndef __ID3D12CommandSignature_INTERFACE_DEFINED__
+#define __ID3D12CommandSignature_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12CommandSignature, 0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("c36a797c-ec80-4f0a-8985-a7b2475082d1")
+ID3D12CommandSignature : public ID3D12Pageable
+{
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12CommandSignature, 0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1)
+#endif
+#else
+typedef struct ID3D12CommandSignatureVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12CommandSignature *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12CommandSignature *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12CommandSignature *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12CommandSignature *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12CommandSignature *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12CommandSignature *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12CommandSignature *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12CommandSignature *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} ID3D12CommandSignatureVtbl;
+
+interface ID3D12CommandSignature {
+    CONST_VTBL ID3D12CommandSignatureVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12CommandSignature_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12CommandSignature_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12CommandSignature_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12CommandSignature_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandSignature_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandSignature_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12CommandSignature_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12CommandSignature_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12CommandSignature_QueryInterface(ID3D12CommandSignature* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12CommandSignature_AddRef(ID3D12CommandSignature* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12CommandSignature_Release(ID3D12CommandSignature* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12CommandSignature_GetPrivateData(ID3D12CommandSignature* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandSignature_SetPrivateData(ID3D12CommandSignature* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandSignature_SetPrivateDataInterface(ID3D12CommandSignature* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandSignature_SetName(ID3D12CommandSignature* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12CommandSignature_GetDevice(ID3D12CommandSignature* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12CommandSignature_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12GraphicsCommandList interface
+ */
+#ifndef __ID3D12GraphicsCommandList_INTERFACE_DEFINED__
+#define __ID3D12GraphicsCommandList_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12GraphicsCommandList, 0x5b160d0f, 0xac1b, 0x4185, 0x8b,0xa8, 0xb3,0xae,0x42,0xa5,0xa4,0x55);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("5b160d0f-ac1b-4185-8ba8-b3ae42a5a455")
+ID3D12GraphicsCommandList : public ID3D12CommandList
+{
+    virtual HRESULT STDMETHODCALLTYPE Close(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Reset(
+        ID3D12CommandAllocator *allocator,
+        ID3D12PipelineState *initial_state) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ClearState(
+        ID3D12PipelineState *pipeline_state) = 0;
+
+    virtual void STDMETHODCALLTYPE DrawInstanced(
+        UINT vertex_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        UINT start_instance_location) = 0;
+
+    virtual void STDMETHODCALLTYPE DrawIndexedInstanced(
+        UINT index_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        INT base_vertex_location,
+        UINT start_instance_location) = 0;
+
+    virtual void STDMETHODCALLTYPE Dispatch(
+        UINT x,
+        UINT u,
+        UINT z) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyBufferRegion(
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT64 byte_count) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyTextureRegion(
+        const D3D12_TEXTURE_COPY_LOCATION *dst,
+        UINT dst_x,
+        UINT dst_y,
+        UINT dst_z,
+        const D3D12_TEXTURE_COPY_LOCATION *src,
+        const D3D12_BOX *src_box) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyResource(
+        ID3D12Resource *dst_resource,
+        ID3D12Resource *src_resource) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyTiles(
+        ID3D12Resource *tiled_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *tile_region_size,
+        ID3D12Resource *buffer,
+        UINT64 buffer_offset,
+        D3D12_TILE_COPY_FLAGS flags) = 0;
+
+    virtual void STDMETHODCALLTYPE ResolveSubresource(
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource,
+        DXGI_FORMAT format) = 0;
+
+    virtual void STDMETHODCALLTYPE IASetPrimitiveTopology(
+        D3D12_PRIMITIVE_TOPOLOGY primitive_topology) = 0;
+
+    virtual void STDMETHODCALLTYPE RSSetViewports(
+        UINT viewport_count,
+        const D3D12_VIEWPORT *viewports) = 0;
+
+    virtual void STDMETHODCALLTYPE RSSetScissorRects(
+        UINT rect_count,
+        const D3D12_RECT *rects) = 0;
+
+    virtual void STDMETHODCALLTYPE OMSetBlendFactor(
+        const FLOAT blend_factor[4]) = 0;
+
+    virtual void STDMETHODCALLTYPE OMSetStencilRef(
+        UINT stencil_ref) = 0;
+
+    virtual void STDMETHODCALLTYPE SetPipelineState(
+        ID3D12PipelineState *pipeline_state) = 0;
+
+    virtual void STDMETHODCALLTYPE ResourceBarrier(
+        UINT barrier_count,
+        const D3D12_RESOURCE_BARRIER *barriers) = 0;
+
+    virtual void STDMETHODCALLTYPE ExecuteBundle(
+        ID3D12GraphicsCommandList *command_list) = 0;
+
+    virtual void STDMETHODCALLTYPE SetDescriptorHeaps(
+        UINT heap_count,
+        ID3D12DescriptorHeap *const *heaps) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRootSignature(
+        ID3D12RootSignature *root_signature) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRootSignature(
+        ID3D12RootSignature *root_signature) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRootDescriptorTable(
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRootDescriptorTable(
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRoot32BitConstant(
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRoot32BitConstant(
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRoot32BitConstants(
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRoot32BitConstants(
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRootConstantBufferView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRootConstantBufferView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRootShaderResourceView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRootShaderResourceView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE SetComputeRootUnorderedAccessView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE SetGraphicsRootUnorderedAccessView(
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address) = 0;
+
+    virtual void STDMETHODCALLTYPE IASetIndexBuffer(
+        const D3D12_INDEX_BUFFER_VIEW *view) = 0;
+
+    virtual void STDMETHODCALLTYPE IASetVertexBuffers(
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_VERTEX_BUFFER_VIEW *views) = 0;
+
+    virtual void STDMETHODCALLTYPE SOSetTargets(
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) = 0;
+
+    virtual void STDMETHODCALLTYPE OMSetRenderTargets(
+        UINT render_target_descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+        BOOL single_descriptor_handle,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE ClearDepthStencilView(
+        D3D12_CPU_DESCRIPTOR_HANDLE dsv,
+        D3D12_CLEAR_FLAGS flags,
+        FLOAT depth,
+        UINT8 stencil,
+        UINT rect_count,
+        const D3D12_RECT *rects) = 0;
+
+    virtual void STDMETHODCALLTYPE ClearRenderTargetView(
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv,
+        const FLOAT color[4],
+        UINT rect_count,
+        const D3D12_RECT *rects) = 0;
+
+    virtual void STDMETHODCALLTYPE ClearUnorderedAccessViewUint(
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const UINT values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects) = 0;
+
+    virtual void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat(
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const float values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects) = 0;
+
+    virtual void STDMETHODCALLTYPE DiscardResource(
+        ID3D12Resource *resource,
+        const D3D12_DISCARD_REGION *region) = 0;
+
+    virtual void STDMETHODCALLTYPE BeginQuery(
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index) = 0;
+
+    virtual void STDMETHODCALLTYPE EndQuery(
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index) = 0;
+
+    virtual void STDMETHODCALLTYPE ResolveQueryData(
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT start_index,
+        UINT query_count,
+        ID3D12Resource *dst_buffer,
+        UINT64 aligned_dst_buffer_offset) = 0;
+
+    virtual void STDMETHODCALLTYPE SetPredication(
+        ID3D12Resource *buffer,
+        UINT64 aligned_buffer_offset,
+        D3D12_PREDICATION_OP operation) = 0;
+
+    virtual void STDMETHODCALLTYPE SetMarker(
+        UINT metadata,
+        const void *data,
+        UINT size) = 0;
+
+    virtual void STDMETHODCALLTYPE BeginEvent(
+        UINT metadata,
+        const void *data,
+        UINT size) = 0;
+
+    virtual void STDMETHODCALLTYPE EndEvent(
+        ) = 0;
+
+    virtual void STDMETHODCALLTYPE ExecuteIndirect(
+        ID3D12CommandSignature *command_signature,
+        UINT max_command_count,
+        ID3D12Resource *arg_buffer,
+        UINT64 arg_buffer_offset,
+        ID3D12Resource *count_buffer,
+        UINT64 count_buffer_offset) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12GraphicsCommandList, 0x5b160d0f, 0xac1b, 0x4185, 0x8b,0xa8, 0xb3,0xae,0x42,0xa5,0xa4,0x55)
+#endif
+#else
+typedef struct ID3D12GraphicsCommandListVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12GraphicsCommandList *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12GraphicsCommandList *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12GraphicsCommandList *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12GraphicsCommandList *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12GraphicsCommandList *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12GraphicsCommandList *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12GraphicsCommandList *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12GraphicsCommandList *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandList methods ***/
+    D3D12_COMMAND_LIST_TYPE (STDMETHODCALLTYPE *GetType)(
+        ID3D12GraphicsCommandList *This);
+
+    /*** ID3D12GraphicsCommandList methods ***/
+    HRESULT (STDMETHODCALLTYPE *Close)(
+        ID3D12GraphicsCommandList *This);
+
+    HRESULT (STDMETHODCALLTYPE *Reset)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12CommandAllocator *allocator,
+        ID3D12PipelineState *initial_state);
+
+    HRESULT (STDMETHODCALLTYPE *ClearState)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *DrawInstanced)(
+        ID3D12GraphicsCommandList *This,
+        UINT vertex_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *DrawIndexedInstanced)(
+        ID3D12GraphicsCommandList *This,
+        UINT index_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        INT base_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *Dispatch)(
+        ID3D12GraphicsCommandList *This,
+        UINT x,
+        UINT u,
+        UINT z);
+
+    void (STDMETHODCALLTYPE *CopyBufferRegion)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT64 byte_count);
+
+    void (STDMETHODCALLTYPE *CopyTextureRegion)(
+        ID3D12GraphicsCommandList *This,
+        const D3D12_TEXTURE_COPY_LOCATION *dst,
+        UINT dst_x,
+        UINT dst_y,
+        UINT dst_z,
+        const D3D12_TEXTURE_COPY_LOCATION *src,
+        const D3D12_BOX *src_box);
+
+    void (STDMETHODCALLTYPE *CopyResource)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *dst_resource,
+        ID3D12Resource *src_resource);
+
+    void (STDMETHODCALLTYPE *CopyTiles)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *tiled_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *tile_region_size,
+        ID3D12Resource *buffer,
+        UINT64 buffer_offset,
+        D3D12_TILE_COPY_FLAGS flags);
+
+    void (STDMETHODCALLTYPE *ResolveSubresource)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource,
+        DXGI_FORMAT format);
+
+    void (STDMETHODCALLTYPE *IASetPrimitiveTopology)(
+        ID3D12GraphicsCommandList *This,
+        D3D12_PRIMITIVE_TOPOLOGY primitive_topology);
+
+    void (STDMETHODCALLTYPE *RSSetViewports)(
+        ID3D12GraphicsCommandList *This,
+        UINT viewport_count,
+        const D3D12_VIEWPORT *viewports);
+
+    void (STDMETHODCALLTYPE *RSSetScissorRects)(
+        ID3D12GraphicsCommandList *This,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *OMSetBlendFactor)(
+        ID3D12GraphicsCommandList *This,
+        const FLOAT blend_factor[4]);
+
+    void (STDMETHODCALLTYPE *OMSetStencilRef)(
+        ID3D12GraphicsCommandList *This,
+        UINT stencil_ref);
+
+    void (STDMETHODCALLTYPE *SetPipelineState)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *ResourceBarrier)(
+        ID3D12GraphicsCommandList *This,
+        UINT barrier_count,
+        const D3D12_RESOURCE_BARRIER *barriers);
+
+    void (STDMETHODCALLTYPE *ExecuteBundle)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12GraphicsCommandList *command_list);
+
+    void (STDMETHODCALLTYPE *SetDescriptorHeaps)(
+        ID3D12GraphicsCommandList *This,
+        UINT heap_count,
+        ID3D12DescriptorHeap *const *heaps);
+
+    void (STDMETHODCALLTYPE *SetComputeRootSignature)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootSignature)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetComputeRootDescriptorTable)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootDescriptorTable)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstant)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstant)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstants)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstants)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRootConstantBufferView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootConstantBufferView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootShaderResourceView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootShaderResourceView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *IASetIndexBuffer)(
+        ID3D12GraphicsCommandList *This,
+        const D3D12_INDEX_BUFFER_VIEW *view);
+
+    void (STDMETHODCALLTYPE *IASetVertexBuffers)(
+        ID3D12GraphicsCommandList *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_VERTEX_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *SOSetTargets)(
+        ID3D12GraphicsCommandList *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *OMSetRenderTargets)(
+        ID3D12GraphicsCommandList *This,
+        UINT render_target_descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+        BOOL single_descriptor_handle,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
+
+    void (STDMETHODCALLTYPE *ClearDepthStencilView)(
+        ID3D12GraphicsCommandList *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE dsv,
+        D3D12_CLEAR_FLAGS flags,
+        FLOAT depth,
+        UINT8 stencil,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearRenderTargetView)(
+        ID3D12GraphicsCommandList *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv,
+        const FLOAT color[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewUint)(
+        ID3D12GraphicsCommandList *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const UINT values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewFloat)(
+        ID3D12GraphicsCommandList *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const float values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *DiscardResource)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *resource,
+        const D3D12_DISCARD_REGION *region);
+
+    void (STDMETHODCALLTYPE *BeginQuery)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *EndQuery)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *ResolveQueryData)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT start_index,
+        UINT query_count,
+        ID3D12Resource *dst_buffer,
+        UINT64 aligned_dst_buffer_offset);
+
+    void (STDMETHODCALLTYPE *SetPredication)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12Resource *buffer,
+        UINT64 aligned_buffer_offset,
+        D3D12_PREDICATION_OP operation);
+
+    void (STDMETHODCALLTYPE *SetMarker)(
+        ID3D12GraphicsCommandList *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *BeginEvent)(
+        ID3D12GraphicsCommandList *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *EndEvent)(
+        ID3D12GraphicsCommandList *This);
+
+    void (STDMETHODCALLTYPE *ExecuteIndirect)(
+        ID3D12GraphicsCommandList *This,
+        ID3D12CommandSignature *command_signature,
+        UINT max_command_count,
+        ID3D12Resource *arg_buffer,
+        UINT64 arg_buffer_offset,
+        ID3D12Resource *count_buffer,
+        UINT64 count_buffer_offset);
+
+    END_INTERFACE
+} ID3D12GraphicsCommandListVtbl;
+
+interface ID3D12GraphicsCommandList {
+    CONST_VTBL ID3D12GraphicsCommandListVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12GraphicsCommandList_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12GraphicsCommandList_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12GraphicsCommandList_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12GraphicsCommandList_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12GraphicsCommandList_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12GraphicsCommandList_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandList methods ***/
+#define ID3D12GraphicsCommandList_GetType(This) (This)->lpVtbl->GetType(This)
+/*** ID3D12GraphicsCommandList methods ***/
+#define ID3D12GraphicsCommandList_Close(This) (This)->lpVtbl->Close(This)
+#define ID3D12GraphicsCommandList_Reset(This,allocator,initial_state) (This)->lpVtbl->Reset(This,allocator,initial_state)
+#define ID3D12GraphicsCommandList_ClearState(This,pipeline_state) (This)->lpVtbl->ClearState(This,pipeline_state)
+#define ID3D12GraphicsCommandList_DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location) (This)->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList_DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location) (This)->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList_Dispatch(This,x,u,z) (This)->lpVtbl->Dispatch(This,x,u,z)
+#define ID3D12GraphicsCommandList_CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count) (This)->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count)
+#define ID3D12GraphicsCommandList_CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box) (This)->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box)
+#define ID3D12GraphicsCommandList_CopyResource(This,dst_resource,src_resource) (This)->lpVtbl->CopyResource(This,dst_resource,src_resource)
+#define ID3D12GraphicsCommandList_CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags) (This)->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags)
+#define ID3D12GraphicsCommandList_ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format) (This)->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format)
+#define ID3D12GraphicsCommandList_IASetPrimitiveTopology(This,primitive_topology) (This)->lpVtbl->IASetPrimitiveTopology(This,primitive_topology)
+#define ID3D12GraphicsCommandList_RSSetViewports(This,viewport_count,viewports) (This)->lpVtbl->RSSetViewports(This,viewport_count,viewports)
+#define ID3D12GraphicsCommandList_RSSetScissorRects(This,rect_count,rects) (This)->lpVtbl->RSSetScissorRects(This,rect_count,rects)
+#define ID3D12GraphicsCommandList_OMSetBlendFactor(This,blend_factor) (This)->lpVtbl->OMSetBlendFactor(This,blend_factor)
+#define ID3D12GraphicsCommandList_OMSetStencilRef(This,stencil_ref) (This)->lpVtbl->OMSetStencilRef(This,stencil_ref)
+#define ID3D12GraphicsCommandList_SetPipelineState(This,pipeline_state) (This)->lpVtbl->SetPipelineState(This,pipeline_state)
+#define ID3D12GraphicsCommandList_ResourceBarrier(This,barrier_count,barriers) (This)->lpVtbl->ResourceBarrier(This,barrier_count,barriers)
+#define ID3D12GraphicsCommandList_ExecuteBundle(This,command_list) (This)->lpVtbl->ExecuteBundle(This,command_list)
+#define ID3D12GraphicsCommandList_SetDescriptorHeaps(This,heap_count,heaps) (This)->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps)
+#define ID3D12GraphicsCommandList_SetComputeRootSignature(This,root_signature) (This)->lpVtbl->SetComputeRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList_SetGraphicsRootSignature(This,root_signature) (This)->lpVtbl->SetGraphicsRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList_SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList_SetComputeRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_SetComputeRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList_IASetIndexBuffer(This,view) (This)->lpVtbl->IASetIndexBuffer(This,view)
+#define ID3D12GraphicsCommandList_IASetVertexBuffers(This,start_slot,view_count,views) (This)->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList_SOSetTargets(This,start_slot,view_count,views) (This)->lpVtbl->SOSetTargets(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList_OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor) (This)->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor)
+#define ID3D12GraphicsCommandList_ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects) (This)->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects)
+#define ID3D12GraphicsCommandList_ClearRenderTargetView(This,rtv,color,rect_count,rects) (This)->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects)
+#define ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList_ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList_DiscardResource(This,resource,region) (This)->lpVtbl->DiscardResource(This,resource,region)
+#define ID3D12GraphicsCommandList_BeginQuery(This,heap,type,index) (This)->lpVtbl->BeginQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList_EndQuery(This,heap,type,index) (This)->lpVtbl->EndQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList_ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset) (This)->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset)
+#define ID3D12GraphicsCommandList_SetPredication(This,buffer,aligned_buffer_offset,operation) (This)->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation)
+#define ID3D12GraphicsCommandList_SetMarker(This,metadata,data,size) (This)->lpVtbl->SetMarker(This,metadata,data,size)
+#define ID3D12GraphicsCommandList_BeginEvent(This,metadata,data,size) (This)->lpVtbl->BeginEvent(This,metadata,data,size)
+#define ID3D12GraphicsCommandList_EndEvent(This) (This)->lpVtbl->EndEvent(This)
+#define ID3D12GraphicsCommandList_ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset) (This)->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_QueryInterface(ID3D12GraphicsCommandList* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList_AddRef(ID3D12GraphicsCommandList* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList_Release(ID3D12GraphicsCommandList* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_GetPrivateData(ID3D12GraphicsCommandList* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_SetPrivateData(ID3D12GraphicsCommandList* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_SetPrivateDataInterface(ID3D12GraphicsCommandList* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_SetName(ID3D12GraphicsCommandList* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_GetDevice(ID3D12GraphicsCommandList* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandList methods ***/
+static FORCEINLINE D3D12_COMMAND_LIST_TYPE ID3D12GraphicsCommandList_GetType(ID3D12GraphicsCommandList* This) {
+    return This->lpVtbl->GetType(This);
+}
+/*** ID3D12GraphicsCommandList methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_Close(ID3D12GraphicsCommandList* This) {
+    return This->lpVtbl->Close(This);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_Reset(ID3D12GraphicsCommandList* This,ID3D12CommandAllocator *allocator,ID3D12PipelineState *initial_state) {
+    return This->lpVtbl->Reset(This,allocator,initial_state);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList_ClearState(ID3D12GraphicsCommandList* This,ID3D12PipelineState *pipeline_state) {
+    return This->lpVtbl->ClearState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_DrawInstanced(ID3D12GraphicsCommandList* This,UINT vertex_count_per_instance,UINT instance_count,UINT start_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_DrawIndexedInstanced(ID3D12GraphicsCommandList* This,UINT index_count_per_instance,UINT instance_count,UINT start_vertex_location,INT base_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_Dispatch(ID3D12GraphicsCommandList* This,UINT x,UINT u,UINT z) {
+    This->lpVtbl->Dispatch(This,x,u,z);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_CopyBufferRegion(ID3D12GraphicsCommandList* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT64 byte_count) {
+    This->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_CopyTextureRegion(ID3D12GraphicsCommandList* This,const D3D12_TEXTURE_COPY_LOCATION *dst,UINT dst_x,UINT dst_y,UINT dst_z,const D3D12_TEXTURE_COPY_LOCATION *src,const D3D12_BOX *src_box) {
+    This->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_CopyResource(ID3D12GraphicsCommandList* This,ID3D12Resource *dst_resource,ID3D12Resource *src_resource) {
+    This->lpVtbl->CopyResource(This,dst_resource,src_resource);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_CopyTiles(ID3D12GraphicsCommandList* This,ID3D12Resource *tiled_resource,const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,const D3D12_TILE_REGION_SIZE *tile_region_size,ID3D12Resource *buffer,UINT64 buffer_offset,D3D12_TILE_COPY_FLAGS flags) {
+    This->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ResolveSubresource(ID3D12GraphicsCommandList* This,ID3D12Resource *dst_resource,UINT dst_sub_resource,ID3D12Resource *src_resource,UINT src_sub_resource,DXGI_FORMAT format) {
+    This->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_IASetPrimitiveTopology(ID3D12GraphicsCommandList* This,D3D12_PRIMITIVE_TOPOLOGY primitive_topology) {
+    This->lpVtbl->IASetPrimitiveTopology(This,primitive_topology);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_RSSetViewports(ID3D12GraphicsCommandList* This,UINT viewport_count,const D3D12_VIEWPORT *viewports) {
+    This->lpVtbl->RSSetViewports(This,viewport_count,viewports);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_RSSetScissorRects(ID3D12GraphicsCommandList* This,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->RSSetScissorRects(This,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_OMSetBlendFactor(ID3D12GraphicsCommandList* This,const FLOAT blend_factor[4]) {
+    This->lpVtbl->OMSetBlendFactor(This,blend_factor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_OMSetStencilRef(ID3D12GraphicsCommandList* This,UINT stencil_ref) {
+    This->lpVtbl->OMSetStencilRef(This,stencil_ref);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetPipelineState(ID3D12GraphicsCommandList* This,ID3D12PipelineState *pipeline_state) {
+    This->lpVtbl->SetPipelineState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ResourceBarrier(ID3D12GraphicsCommandList* This,UINT barrier_count,const D3D12_RESOURCE_BARRIER *barriers) {
+    This->lpVtbl->ResourceBarrier(This,barrier_count,barriers);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ExecuteBundle(ID3D12GraphicsCommandList* This,ID3D12GraphicsCommandList *command_list) {
+    This->lpVtbl->ExecuteBundle(This,command_list);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetDescriptorHeaps(ID3D12GraphicsCommandList* This,UINT heap_count,ID3D12DescriptorHeap *const *heaps) {
+    This->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRootSignature(ID3D12GraphicsCommandList* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetComputeRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRootSignature(ID3D12GraphicsCommandList* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetGraphicsRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRootConstantBufferView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRootShaderResourceView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetGraphicsRootUnorderedAccessView(ID3D12GraphicsCommandList* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_IASetIndexBuffer(ID3D12GraphicsCommandList* This,const D3D12_INDEX_BUFFER_VIEW *view) {
+    This->lpVtbl->IASetIndexBuffer(This,view);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_IASetVertexBuffers(ID3D12GraphicsCommandList* This,UINT start_slot,UINT view_count,const D3D12_VERTEX_BUFFER_VIEW *views) {
+    This->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SOSetTargets(ID3D12GraphicsCommandList* This,UINT start_slot,UINT view_count,const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) {
+    This->lpVtbl->SOSetTargets(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_OMSetRenderTargets(ID3D12GraphicsCommandList* This,UINT render_target_descriptor_count,const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,BOOL single_descriptor_handle,const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
+    This->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ClearDepthStencilView(ID3D12GraphicsCommandList* This,D3D12_CPU_DESCRIPTOR_HANDLE dsv,D3D12_CLEAR_FLAGS flags,FLOAT depth,UINT8 stencil,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ClearRenderTargetView(ID3D12GraphicsCommandList* This,D3D12_CPU_DESCRIPTOR_HANDLE rtv,const FLOAT color[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const UINT values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const float values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_DiscardResource(ID3D12GraphicsCommandList* This,ID3D12Resource *resource,const D3D12_DISCARD_REGION *region) {
+    This->lpVtbl->DiscardResource(This,resource,region);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_BeginQuery(ID3D12GraphicsCommandList* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->BeginQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_EndQuery(ID3D12GraphicsCommandList* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->EndQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ResolveQueryData(ID3D12GraphicsCommandList* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT start_index,UINT query_count,ID3D12Resource *dst_buffer,UINT64 aligned_dst_buffer_offset) {
+    This->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetPredication(ID3D12GraphicsCommandList* This,ID3D12Resource *buffer,UINT64 aligned_buffer_offset,D3D12_PREDICATION_OP operation) {
+    This->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_SetMarker(ID3D12GraphicsCommandList* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->SetMarker(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_BeginEvent(ID3D12GraphicsCommandList* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->BeginEvent(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_EndEvent(ID3D12GraphicsCommandList* This) {
+    This->lpVtbl->EndEvent(This);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList_ExecuteIndirect(ID3D12GraphicsCommandList* This,ID3D12CommandSignature *command_signature,UINT max_command_count,ID3D12Resource *arg_buffer,UINT64 arg_buffer_offset,ID3D12Resource *count_buffer,UINT64 count_buffer_offset) {
+    This->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12GraphicsCommandList_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12GraphicsCommandList1 interface
+ */
+#ifndef __ID3D12GraphicsCommandList1_INTERFACE_DEFINED__
+#define __ID3D12GraphicsCommandList1_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12GraphicsCommandList1, 0x553103fb, 0x1fe7, 0x4557, 0xbb,0x38, 0x94,0x6d,0x7d,0x0e,0x7c,0xa7);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("553103fb-1fe7-4557-bb38-946d7d0e7ca7")
+ID3D12GraphicsCommandList1 : public ID3D12GraphicsCommandList
+{
+    virtual void STDMETHODCALLTYPE AtomicCopyBufferUINT(
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) = 0;
+
+    virtual void STDMETHODCALLTYPE AtomicCopyBufferUINT64(
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) = 0;
+
+    virtual void STDMETHODCALLTYPE OMSetDepthBounds(
+        FLOAT min,
+        FLOAT max) = 0;
+
+    virtual void STDMETHODCALLTYPE SetSamplePositions(
+        UINT sample_count,
+        UINT pixel_count,
+        D3D12_SAMPLE_POSITION *sample_positions) = 0;
+
+    virtual void STDMETHODCALLTYPE ResolveSubresourceRegion(
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource_idx,
+        UINT dst_x,
+        UINT dst_y,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource_idx,
+        D3D12_RECT *src_rect,
+        DXGI_FORMAT format,
+        D3D12_RESOLVE_MODE mode) = 0;
+
+    virtual void STDMETHODCALLTYPE SetViewInstanceMask(
+        UINT mask) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12GraphicsCommandList1, 0x553103fb, 0x1fe7, 0x4557, 0xbb,0x38, 0x94,0x6d,0x7d,0x0e,0x7c,0xa7)
+#endif
+#else
+typedef struct ID3D12GraphicsCommandList1Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12GraphicsCommandList1 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12GraphicsCommandList1 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12GraphicsCommandList1 *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12GraphicsCommandList1 *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12GraphicsCommandList1 *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12GraphicsCommandList1 *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12GraphicsCommandList1 *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12GraphicsCommandList1 *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandList methods ***/
+    D3D12_COMMAND_LIST_TYPE (STDMETHODCALLTYPE *GetType)(
+        ID3D12GraphicsCommandList1 *This);
+
+    /*** ID3D12GraphicsCommandList methods ***/
+    HRESULT (STDMETHODCALLTYPE *Close)(
+        ID3D12GraphicsCommandList1 *This);
+
+    HRESULT (STDMETHODCALLTYPE *Reset)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12CommandAllocator *allocator,
+        ID3D12PipelineState *initial_state);
+
+    HRESULT (STDMETHODCALLTYPE *ClearState)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *DrawInstanced)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT vertex_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *DrawIndexedInstanced)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT index_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        INT base_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *Dispatch)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT x,
+        UINT u,
+        UINT z);
+
+    void (STDMETHODCALLTYPE *CopyBufferRegion)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT64 byte_count);
+
+    void (STDMETHODCALLTYPE *CopyTextureRegion)(
+        ID3D12GraphicsCommandList1 *This,
+        const D3D12_TEXTURE_COPY_LOCATION *dst,
+        UINT dst_x,
+        UINT dst_y,
+        UINT dst_z,
+        const D3D12_TEXTURE_COPY_LOCATION *src,
+        const D3D12_BOX *src_box);
+
+    void (STDMETHODCALLTYPE *CopyResource)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_resource,
+        ID3D12Resource *src_resource);
+
+    void (STDMETHODCALLTYPE *CopyTiles)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *tiled_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *tile_region_size,
+        ID3D12Resource *buffer,
+        UINT64 buffer_offset,
+        D3D12_TILE_COPY_FLAGS flags);
+
+    void (STDMETHODCALLTYPE *ResolveSubresource)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource,
+        DXGI_FORMAT format);
+
+    void (STDMETHODCALLTYPE *IASetPrimitiveTopology)(
+        ID3D12GraphicsCommandList1 *This,
+        D3D12_PRIMITIVE_TOPOLOGY primitive_topology);
+
+    void (STDMETHODCALLTYPE *RSSetViewports)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT viewport_count,
+        const D3D12_VIEWPORT *viewports);
+
+    void (STDMETHODCALLTYPE *RSSetScissorRects)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *OMSetBlendFactor)(
+        ID3D12GraphicsCommandList1 *This,
+        const FLOAT blend_factor[4]);
+
+    void (STDMETHODCALLTYPE *OMSetStencilRef)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT stencil_ref);
+
+    void (STDMETHODCALLTYPE *SetPipelineState)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *ResourceBarrier)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT barrier_count,
+        const D3D12_RESOURCE_BARRIER *barriers);
+
+    void (STDMETHODCALLTYPE *ExecuteBundle)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12GraphicsCommandList *command_list);
+
+    void (STDMETHODCALLTYPE *SetDescriptorHeaps)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT heap_count,
+        ID3D12DescriptorHeap *const *heaps);
+
+    void (STDMETHODCALLTYPE *SetComputeRootSignature)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootSignature)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetComputeRootDescriptorTable)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootDescriptorTable)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstant)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstant)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstants)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstants)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRootConstantBufferView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootConstantBufferView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootShaderResourceView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootShaderResourceView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *IASetIndexBuffer)(
+        ID3D12GraphicsCommandList1 *This,
+        const D3D12_INDEX_BUFFER_VIEW *view);
+
+    void (STDMETHODCALLTYPE *IASetVertexBuffers)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_VERTEX_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *SOSetTargets)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *OMSetRenderTargets)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT render_target_descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+        BOOL single_descriptor_handle,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
+
+    void (STDMETHODCALLTYPE *ClearDepthStencilView)(
+        ID3D12GraphicsCommandList1 *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE dsv,
+        D3D12_CLEAR_FLAGS flags,
+        FLOAT depth,
+        UINT8 stencil,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearRenderTargetView)(
+        ID3D12GraphicsCommandList1 *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv,
+        const FLOAT color[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewUint)(
+        ID3D12GraphicsCommandList1 *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const UINT values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewFloat)(
+        ID3D12GraphicsCommandList1 *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const float values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *DiscardResource)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *resource,
+        const D3D12_DISCARD_REGION *region);
+
+    void (STDMETHODCALLTYPE *BeginQuery)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *EndQuery)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *ResolveQueryData)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT start_index,
+        UINT query_count,
+        ID3D12Resource *dst_buffer,
+        UINT64 aligned_dst_buffer_offset);
+
+    void (STDMETHODCALLTYPE *SetPredication)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *buffer,
+        UINT64 aligned_buffer_offset,
+        D3D12_PREDICATION_OP operation);
+
+    void (STDMETHODCALLTYPE *SetMarker)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *BeginEvent)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *EndEvent)(
+        ID3D12GraphicsCommandList1 *This);
+
+    void (STDMETHODCALLTYPE *ExecuteIndirect)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12CommandSignature *command_signature,
+        UINT max_command_count,
+        ID3D12Resource *arg_buffer,
+        UINT64 arg_buffer_offset,
+        ID3D12Resource *count_buffer,
+        UINT64 count_buffer_offset);
+
+    /*** ID3D12GraphicsCommandList1 methods ***/
+    void (STDMETHODCALLTYPE *AtomicCopyBufferUINT)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void (STDMETHODCALLTYPE *AtomicCopyBufferUINT64)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void (STDMETHODCALLTYPE *OMSetDepthBounds)(
+        ID3D12GraphicsCommandList1 *This,
+        FLOAT min,
+        FLOAT max);
+
+    void (STDMETHODCALLTYPE *SetSamplePositions)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT sample_count,
+        UINT pixel_count,
+        D3D12_SAMPLE_POSITION *sample_positions);
+
+    void (STDMETHODCALLTYPE *ResolveSubresourceRegion)(
+        ID3D12GraphicsCommandList1 *This,
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource_idx,
+        UINT dst_x,
+        UINT dst_y,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource_idx,
+        D3D12_RECT *src_rect,
+        DXGI_FORMAT format,
+        D3D12_RESOLVE_MODE mode);
+
+    void (STDMETHODCALLTYPE *SetViewInstanceMask)(
+        ID3D12GraphicsCommandList1 *This,
+        UINT mask);
+
+    END_INTERFACE
+} ID3D12GraphicsCommandList1Vtbl;
+
+interface ID3D12GraphicsCommandList1 {
+    CONST_VTBL ID3D12GraphicsCommandList1Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12GraphicsCommandList1_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12GraphicsCommandList1_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12GraphicsCommandList1_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12GraphicsCommandList1_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList1_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList1_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12GraphicsCommandList1_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12GraphicsCommandList1_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandList methods ***/
+#define ID3D12GraphicsCommandList1_GetType(This) (This)->lpVtbl->GetType(This)
+/*** ID3D12GraphicsCommandList methods ***/
+#define ID3D12GraphicsCommandList1_Close(This) (This)->lpVtbl->Close(This)
+#define ID3D12GraphicsCommandList1_Reset(This,allocator,initial_state) (This)->lpVtbl->Reset(This,allocator,initial_state)
+#define ID3D12GraphicsCommandList1_ClearState(This,pipeline_state) (This)->lpVtbl->ClearState(This,pipeline_state)
+#define ID3D12GraphicsCommandList1_DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location) (This)->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList1_DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location) (This)->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList1_Dispatch(This,x,u,z) (This)->lpVtbl->Dispatch(This,x,u,z)
+#define ID3D12GraphicsCommandList1_CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count) (This)->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count)
+#define ID3D12GraphicsCommandList1_CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box) (This)->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box)
+#define ID3D12GraphicsCommandList1_CopyResource(This,dst_resource,src_resource) (This)->lpVtbl->CopyResource(This,dst_resource,src_resource)
+#define ID3D12GraphicsCommandList1_CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags) (This)->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags)
+#define ID3D12GraphicsCommandList1_ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format) (This)->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format)
+#define ID3D12GraphicsCommandList1_IASetPrimitiveTopology(This,primitive_topology) (This)->lpVtbl->IASetPrimitiveTopology(This,primitive_topology)
+#define ID3D12GraphicsCommandList1_RSSetViewports(This,viewport_count,viewports) (This)->lpVtbl->RSSetViewports(This,viewport_count,viewports)
+#define ID3D12GraphicsCommandList1_RSSetScissorRects(This,rect_count,rects) (This)->lpVtbl->RSSetScissorRects(This,rect_count,rects)
+#define ID3D12GraphicsCommandList1_OMSetBlendFactor(This,blend_factor) (This)->lpVtbl->OMSetBlendFactor(This,blend_factor)
+#define ID3D12GraphicsCommandList1_OMSetStencilRef(This,stencil_ref) (This)->lpVtbl->OMSetStencilRef(This,stencil_ref)
+#define ID3D12GraphicsCommandList1_SetPipelineState(This,pipeline_state) (This)->lpVtbl->SetPipelineState(This,pipeline_state)
+#define ID3D12GraphicsCommandList1_ResourceBarrier(This,barrier_count,barriers) (This)->lpVtbl->ResourceBarrier(This,barrier_count,barriers)
+#define ID3D12GraphicsCommandList1_ExecuteBundle(This,command_list) (This)->lpVtbl->ExecuteBundle(This,command_list)
+#define ID3D12GraphicsCommandList1_SetDescriptorHeaps(This,heap_count,heaps) (This)->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps)
+#define ID3D12GraphicsCommandList1_SetComputeRootSignature(This,root_signature) (This)->lpVtbl->SetComputeRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList1_SetGraphicsRootSignature(This,root_signature) (This)->lpVtbl->SetGraphicsRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList1_SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList1_SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList1_SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList1_SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList1_SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList1_SetComputeRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_SetGraphicsRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_SetGraphicsRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList1_IASetIndexBuffer(This,view) (This)->lpVtbl->IASetIndexBuffer(This,view)
+#define ID3D12GraphicsCommandList1_IASetVertexBuffers(This,start_slot,view_count,views) (This)->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList1_SOSetTargets(This,start_slot,view_count,views) (This)->lpVtbl->SOSetTargets(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList1_OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor) (This)->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor)
+#define ID3D12GraphicsCommandList1_ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects) (This)->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects)
+#define ID3D12GraphicsCommandList1_ClearRenderTargetView(This,rtv,color,rect_count,rects) (This)->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects)
+#define ID3D12GraphicsCommandList1_ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList1_ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList1_DiscardResource(This,resource,region) (This)->lpVtbl->DiscardResource(This,resource,region)
+#define ID3D12GraphicsCommandList1_BeginQuery(This,heap,type,index) (This)->lpVtbl->BeginQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList1_EndQuery(This,heap,type,index) (This)->lpVtbl->EndQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList1_ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset) (This)->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset)
+#define ID3D12GraphicsCommandList1_SetPredication(This,buffer,aligned_buffer_offset,operation) (This)->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation)
+#define ID3D12GraphicsCommandList1_SetMarker(This,metadata,data,size) (This)->lpVtbl->SetMarker(This,metadata,data,size)
+#define ID3D12GraphicsCommandList1_BeginEvent(This,metadata,data,size) (This)->lpVtbl->BeginEvent(This,metadata,data,size)
+#define ID3D12GraphicsCommandList1_EndEvent(This) (This)->lpVtbl->EndEvent(This)
+#define ID3D12GraphicsCommandList1_ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset) (This)->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset)
+/*** ID3D12GraphicsCommandList1 methods ***/
+#define ID3D12GraphicsCommandList1_AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges) (This)->lpVtbl->AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges)
+#define ID3D12GraphicsCommandList1_AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges) (This)->lpVtbl->AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges)
+#define ID3D12GraphicsCommandList1_OMSetDepthBounds(This,min,max) (This)->lpVtbl->OMSetDepthBounds(This,min,max)
+#define ID3D12GraphicsCommandList1_SetSamplePositions(This,sample_count,pixel_count,sample_positions) (This)->lpVtbl->SetSamplePositions(This,sample_count,pixel_count,sample_positions)
+#define ID3D12GraphicsCommandList1_ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode) (This)->lpVtbl->ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode)
+#define ID3D12GraphicsCommandList1_SetViewInstanceMask(This,mask) (This)->lpVtbl->SetViewInstanceMask(This,mask)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_QueryInterface(ID3D12GraphicsCommandList1* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList1_AddRef(ID3D12GraphicsCommandList1* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList1_Release(ID3D12GraphicsCommandList1* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_GetPrivateData(ID3D12GraphicsCommandList1* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_SetPrivateData(ID3D12GraphicsCommandList1* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_SetPrivateDataInterface(ID3D12GraphicsCommandList1* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_SetName(ID3D12GraphicsCommandList1* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_GetDevice(ID3D12GraphicsCommandList1* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandList methods ***/
+static FORCEINLINE D3D12_COMMAND_LIST_TYPE ID3D12GraphicsCommandList1_GetType(ID3D12GraphicsCommandList1* This) {
+    return This->lpVtbl->GetType(This);
+}
+/*** ID3D12GraphicsCommandList methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_Close(ID3D12GraphicsCommandList1* This) {
+    return This->lpVtbl->Close(This);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_Reset(ID3D12GraphicsCommandList1* This,ID3D12CommandAllocator *allocator,ID3D12PipelineState *initial_state) {
+    return This->lpVtbl->Reset(This,allocator,initial_state);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList1_ClearState(ID3D12GraphicsCommandList1* This,ID3D12PipelineState *pipeline_state) {
+    return This->lpVtbl->ClearState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_DrawInstanced(ID3D12GraphicsCommandList1* This,UINT vertex_count_per_instance,UINT instance_count,UINT start_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_DrawIndexedInstanced(ID3D12GraphicsCommandList1* This,UINT index_count_per_instance,UINT instance_count,UINT start_vertex_location,INT base_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_Dispatch(ID3D12GraphicsCommandList1* This,UINT x,UINT u,UINT z) {
+    This->lpVtbl->Dispatch(This,x,u,z);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_CopyBufferRegion(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT64 byte_count) {
+    This->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_CopyTextureRegion(ID3D12GraphicsCommandList1* This,const D3D12_TEXTURE_COPY_LOCATION *dst,UINT dst_x,UINT dst_y,UINT dst_z,const D3D12_TEXTURE_COPY_LOCATION *src,const D3D12_BOX *src_box) {
+    This->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_CopyResource(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_resource,ID3D12Resource *src_resource) {
+    This->lpVtbl->CopyResource(This,dst_resource,src_resource);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_CopyTiles(ID3D12GraphicsCommandList1* This,ID3D12Resource *tiled_resource,const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,const D3D12_TILE_REGION_SIZE *tile_region_size,ID3D12Resource *buffer,UINT64 buffer_offset,D3D12_TILE_COPY_FLAGS flags) {
+    This->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ResolveSubresource(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_resource,UINT dst_sub_resource,ID3D12Resource *src_resource,UINT src_sub_resource,DXGI_FORMAT format) {
+    This->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_IASetPrimitiveTopology(ID3D12GraphicsCommandList1* This,D3D12_PRIMITIVE_TOPOLOGY primitive_topology) {
+    This->lpVtbl->IASetPrimitiveTopology(This,primitive_topology);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_RSSetViewports(ID3D12GraphicsCommandList1* This,UINT viewport_count,const D3D12_VIEWPORT *viewports) {
+    This->lpVtbl->RSSetViewports(This,viewport_count,viewports);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_RSSetScissorRects(ID3D12GraphicsCommandList1* This,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->RSSetScissorRects(This,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_OMSetBlendFactor(ID3D12GraphicsCommandList1* This,const FLOAT blend_factor[4]) {
+    This->lpVtbl->OMSetBlendFactor(This,blend_factor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_OMSetStencilRef(ID3D12GraphicsCommandList1* This,UINT stencil_ref) {
+    This->lpVtbl->OMSetStencilRef(This,stencil_ref);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetPipelineState(ID3D12GraphicsCommandList1* This,ID3D12PipelineState *pipeline_state) {
+    This->lpVtbl->SetPipelineState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ResourceBarrier(ID3D12GraphicsCommandList1* This,UINT barrier_count,const D3D12_RESOURCE_BARRIER *barriers) {
+    This->lpVtbl->ResourceBarrier(This,barrier_count,barriers);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ExecuteBundle(ID3D12GraphicsCommandList1* This,ID3D12GraphicsCommandList *command_list) {
+    This->lpVtbl->ExecuteBundle(This,command_list);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetDescriptorHeaps(ID3D12GraphicsCommandList1* This,UINT heap_count,ID3D12DescriptorHeap *const *heaps) {
+    This->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRootSignature(ID3D12GraphicsCommandList1* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetComputeRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRootSignature(ID3D12GraphicsCommandList1* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetGraphicsRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRootConstantBufferView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRootConstantBufferView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRootShaderResourceView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetGraphicsRootUnorderedAccessView(ID3D12GraphicsCommandList1* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_IASetIndexBuffer(ID3D12GraphicsCommandList1* This,const D3D12_INDEX_BUFFER_VIEW *view) {
+    This->lpVtbl->IASetIndexBuffer(This,view);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_IASetVertexBuffers(ID3D12GraphicsCommandList1* This,UINT start_slot,UINT view_count,const D3D12_VERTEX_BUFFER_VIEW *views) {
+    This->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SOSetTargets(ID3D12GraphicsCommandList1* This,UINT start_slot,UINT view_count,const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) {
+    This->lpVtbl->SOSetTargets(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_OMSetRenderTargets(ID3D12GraphicsCommandList1* This,UINT render_target_descriptor_count,const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,BOOL single_descriptor_handle,const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
+    This->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ClearDepthStencilView(ID3D12GraphicsCommandList1* This,D3D12_CPU_DESCRIPTOR_HANDLE dsv,D3D12_CLEAR_FLAGS flags,FLOAT depth,UINT8 stencil,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ClearRenderTargetView(ID3D12GraphicsCommandList1* This,D3D12_CPU_DESCRIPTOR_HANDLE rtv,const FLOAT color[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList1* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const UINT values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList1* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const float values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_DiscardResource(ID3D12GraphicsCommandList1* This,ID3D12Resource *resource,const D3D12_DISCARD_REGION *region) {
+    This->lpVtbl->DiscardResource(This,resource,region);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_BeginQuery(ID3D12GraphicsCommandList1* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->BeginQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_EndQuery(ID3D12GraphicsCommandList1* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->EndQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ResolveQueryData(ID3D12GraphicsCommandList1* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT start_index,UINT query_count,ID3D12Resource *dst_buffer,UINT64 aligned_dst_buffer_offset) {
+    This->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetPredication(ID3D12GraphicsCommandList1* This,ID3D12Resource *buffer,UINT64 aligned_buffer_offset,D3D12_PREDICATION_OP operation) {
+    This->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetMarker(ID3D12GraphicsCommandList1* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->SetMarker(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_BeginEvent(ID3D12GraphicsCommandList1* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->BeginEvent(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_EndEvent(ID3D12GraphicsCommandList1* This) {
+    This->lpVtbl->EndEvent(This);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ExecuteIndirect(ID3D12GraphicsCommandList1* This,ID3D12CommandSignature *command_signature,UINT max_command_count,ID3D12Resource *arg_buffer,UINT64 arg_buffer_offset,ID3D12Resource *count_buffer,UINT64 count_buffer_offset) {
+    This->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset);
+}
+/*** ID3D12GraphicsCommandList1 methods ***/
+static FORCEINLINE void ID3D12GraphicsCommandList1_AtomicCopyBufferUINT(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT dependent_resource_count,ID3D12Resource *const *dependent_resources,const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
+    This->lpVtbl->AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT dependent_resource_count,ID3D12Resource *const *dependent_resources,const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
+    This->lpVtbl->AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_OMSetDepthBounds(ID3D12GraphicsCommandList1* This,FLOAT min,FLOAT max) {
+    This->lpVtbl->OMSetDepthBounds(This,min,max);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetSamplePositions(ID3D12GraphicsCommandList1* This,UINT sample_count,UINT pixel_count,D3D12_SAMPLE_POSITION *sample_positions) {
+    This->lpVtbl->SetSamplePositions(This,sample_count,pixel_count,sample_positions);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_ResolveSubresourceRegion(ID3D12GraphicsCommandList1* This,ID3D12Resource *dst_resource,UINT dst_sub_resource_idx,UINT dst_x,UINT dst_y,ID3D12Resource *src_resource,UINT src_sub_resource_idx,D3D12_RECT *src_rect,DXGI_FORMAT format,D3D12_RESOLVE_MODE mode) {
+    This->lpVtbl->ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList1_SetViewInstanceMask(ID3D12GraphicsCommandList1* This,UINT mask) {
+    This->lpVtbl->SetViewInstanceMask(This,mask);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12GraphicsCommandList1_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12GraphicsCommandList2 interface
+ */
+#ifndef __ID3D12GraphicsCommandList2_INTERFACE_DEFINED__
+#define __ID3D12GraphicsCommandList2_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12GraphicsCommandList2, 0x38c3e585, 0xff17, 0x412c, 0x91,0x50, 0x4f,0xc6,0xf9,0xd7,0x2a,0x28);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("38c3e585-ff17-412c-9150-4fc6f9d72a28")
+ID3D12GraphicsCommandList2 : public ID3D12GraphicsCommandList1
+{
+    virtual void STDMETHODCALLTYPE WriteBufferImmediate(
+        UINT count,
+        const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters,
+        const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12GraphicsCommandList2, 0x38c3e585, 0xff17, 0x412c, 0x91,0x50, 0x4f,0xc6,0xf9,0xd7,0x2a,0x28)
+#endif
+#else
+typedef struct ID3D12GraphicsCommandList2Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12GraphicsCommandList2 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12GraphicsCommandList2 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12GraphicsCommandList2 *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12GraphicsCommandList2 *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12GraphicsCommandList2 *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12GraphicsCommandList2 *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12GraphicsCommandList2 *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12GraphicsCommandList2 *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandList methods ***/
+    D3D12_COMMAND_LIST_TYPE (STDMETHODCALLTYPE *GetType)(
+        ID3D12GraphicsCommandList2 *This);
+
+    /*** ID3D12GraphicsCommandList methods ***/
+    HRESULT (STDMETHODCALLTYPE *Close)(
+        ID3D12GraphicsCommandList2 *This);
+
+    HRESULT (STDMETHODCALLTYPE *Reset)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12CommandAllocator *allocator,
+        ID3D12PipelineState *initial_state);
+
+    HRESULT (STDMETHODCALLTYPE *ClearState)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *DrawInstanced)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT vertex_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *DrawIndexedInstanced)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT index_count_per_instance,
+        UINT instance_count,
+        UINT start_vertex_location,
+        INT base_vertex_location,
+        UINT start_instance_location);
+
+    void (STDMETHODCALLTYPE *Dispatch)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT x,
+        UINT u,
+        UINT z);
+
+    void (STDMETHODCALLTYPE *CopyBufferRegion)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT64 byte_count);
+
+    void (STDMETHODCALLTYPE *CopyTextureRegion)(
+        ID3D12GraphicsCommandList2 *This,
+        const D3D12_TEXTURE_COPY_LOCATION *dst,
+        UINT dst_x,
+        UINT dst_y,
+        UINT dst_z,
+        const D3D12_TEXTURE_COPY_LOCATION *src,
+        const D3D12_BOX *src_box);
+
+    void (STDMETHODCALLTYPE *CopyResource)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_resource,
+        ID3D12Resource *src_resource);
+
+    void (STDMETHODCALLTYPE *CopyTiles)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *tiled_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *tile_region_size,
+        ID3D12Resource *buffer,
+        UINT64 buffer_offset,
+        D3D12_TILE_COPY_FLAGS flags);
+
+    void (STDMETHODCALLTYPE *ResolveSubresource)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource,
+        DXGI_FORMAT format);
+
+    void (STDMETHODCALLTYPE *IASetPrimitiveTopology)(
+        ID3D12GraphicsCommandList2 *This,
+        D3D12_PRIMITIVE_TOPOLOGY primitive_topology);
+
+    void (STDMETHODCALLTYPE *RSSetViewports)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT viewport_count,
+        const D3D12_VIEWPORT *viewports);
+
+    void (STDMETHODCALLTYPE *RSSetScissorRects)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *OMSetBlendFactor)(
+        ID3D12GraphicsCommandList2 *This,
+        const FLOAT blend_factor[4]);
+
+    void (STDMETHODCALLTYPE *OMSetStencilRef)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT stencil_ref);
+
+    void (STDMETHODCALLTYPE *SetPipelineState)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12PipelineState *pipeline_state);
+
+    void (STDMETHODCALLTYPE *ResourceBarrier)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT barrier_count,
+        const D3D12_RESOURCE_BARRIER *barriers);
+
+    void (STDMETHODCALLTYPE *ExecuteBundle)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12GraphicsCommandList *command_list);
+
+    void (STDMETHODCALLTYPE *SetDescriptorHeaps)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT heap_count,
+        ID3D12DescriptorHeap *const *heaps);
+
+    void (STDMETHODCALLTYPE *SetComputeRootSignature)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootSignature)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12RootSignature *root_signature);
+
+    void (STDMETHODCALLTYPE *SetComputeRootDescriptorTable)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootDescriptorTable)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstant)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstant)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        UINT data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRoot32BitConstants)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRoot32BitConstants)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        UINT constant_count,
+        const void *data,
+        UINT dst_offset);
+
+    void (STDMETHODCALLTYPE *SetComputeRootConstantBufferView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootConstantBufferView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootShaderResourceView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootShaderResourceView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetComputeRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *SetGraphicsRootUnorderedAccessView)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT root_parameter_index,
+        D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void (STDMETHODCALLTYPE *IASetIndexBuffer)(
+        ID3D12GraphicsCommandList2 *This,
+        const D3D12_INDEX_BUFFER_VIEW *view);
+
+    void (STDMETHODCALLTYPE *IASetVertexBuffers)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_VERTEX_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *SOSetTargets)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT start_slot,
+        UINT view_count,
+        const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views);
+
+    void (STDMETHODCALLTYPE *OMSetRenderTargets)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT render_target_descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+        BOOL single_descriptor_handle,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
+
+    void (STDMETHODCALLTYPE *ClearDepthStencilView)(
+        ID3D12GraphicsCommandList2 *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE dsv,
+        D3D12_CLEAR_FLAGS flags,
+        FLOAT depth,
+        UINT8 stencil,
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearRenderTargetView)(
+        ID3D12GraphicsCommandList2 *This,
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv,
+        const FLOAT color[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewUint)(
+        ID3D12GraphicsCommandList2 *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const UINT values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *ClearUnorderedAccessViewFloat)(
+        ID3D12GraphicsCommandList2 *This,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,
+        ID3D12Resource *resource,
+        const float values[4],
+        UINT rect_count,
+        const D3D12_RECT *rects);
+
+    void (STDMETHODCALLTYPE *DiscardResource)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *resource,
+        const D3D12_DISCARD_REGION *region);
+
+    void (STDMETHODCALLTYPE *BeginQuery)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *EndQuery)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT index);
+
+    void (STDMETHODCALLTYPE *ResolveQueryData)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12QueryHeap *heap,
+        D3D12_QUERY_TYPE type,
+        UINT start_index,
+        UINT query_count,
+        ID3D12Resource *dst_buffer,
+        UINT64 aligned_dst_buffer_offset);
+
+    void (STDMETHODCALLTYPE *SetPredication)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *buffer,
+        UINT64 aligned_buffer_offset,
+        D3D12_PREDICATION_OP operation);
+
+    void (STDMETHODCALLTYPE *SetMarker)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *BeginEvent)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *EndEvent)(
+        ID3D12GraphicsCommandList2 *This);
+
+    void (STDMETHODCALLTYPE *ExecuteIndirect)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12CommandSignature *command_signature,
+        UINT max_command_count,
+        ID3D12Resource *arg_buffer,
+        UINT64 arg_buffer_offset,
+        ID3D12Resource *count_buffer,
+        UINT64 count_buffer_offset);
+
+    /*** ID3D12GraphicsCommandList1 methods ***/
+    void (STDMETHODCALLTYPE *AtomicCopyBufferUINT)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void (STDMETHODCALLTYPE *AtomicCopyBufferUINT64)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_buffer,
+        UINT64 dst_offset,
+        ID3D12Resource *src_buffer,
+        UINT64 src_offset,
+        UINT dependent_resource_count,
+        ID3D12Resource *const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void (STDMETHODCALLTYPE *OMSetDepthBounds)(
+        ID3D12GraphicsCommandList2 *This,
+        FLOAT min,
+        FLOAT max);
+
+    void (STDMETHODCALLTYPE *SetSamplePositions)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT sample_count,
+        UINT pixel_count,
+        D3D12_SAMPLE_POSITION *sample_positions);
+
+    void (STDMETHODCALLTYPE *ResolveSubresourceRegion)(
+        ID3D12GraphicsCommandList2 *This,
+        ID3D12Resource *dst_resource,
+        UINT dst_sub_resource_idx,
+        UINT dst_x,
+        UINT dst_y,
+        ID3D12Resource *src_resource,
+        UINT src_sub_resource_idx,
+        D3D12_RECT *src_rect,
+        DXGI_FORMAT format,
+        D3D12_RESOLVE_MODE mode);
+
+    void (STDMETHODCALLTYPE *SetViewInstanceMask)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT mask);
+
+    /*** ID3D12GraphicsCommandList2 methods ***/
+    void (STDMETHODCALLTYPE *WriteBufferImmediate)(
+        ID3D12GraphicsCommandList2 *This,
+        UINT count,
+        const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters,
+        const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes);
+
+    END_INTERFACE
+} ID3D12GraphicsCommandList2Vtbl;
+
+interface ID3D12GraphicsCommandList2 {
+    CONST_VTBL ID3D12GraphicsCommandList2Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12GraphicsCommandList2_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12GraphicsCommandList2_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12GraphicsCommandList2_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12GraphicsCommandList2_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList2_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12GraphicsCommandList2_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12GraphicsCommandList2_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12GraphicsCommandList2_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandList methods ***/
+#define ID3D12GraphicsCommandList2_GetType(This) (This)->lpVtbl->GetType(This)
+/*** ID3D12GraphicsCommandList methods ***/
+#define ID3D12GraphicsCommandList2_Close(This) (This)->lpVtbl->Close(This)
+#define ID3D12GraphicsCommandList2_Reset(This,allocator,initial_state) (This)->lpVtbl->Reset(This,allocator,initial_state)
+#define ID3D12GraphicsCommandList2_ClearState(This,pipeline_state) (This)->lpVtbl->ClearState(This,pipeline_state)
+#define ID3D12GraphicsCommandList2_DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location) (This)->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList2_DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location) (This)->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location)
+#define ID3D12GraphicsCommandList2_Dispatch(This,x,u,z) (This)->lpVtbl->Dispatch(This,x,u,z)
+#define ID3D12GraphicsCommandList2_CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count) (This)->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count)
+#define ID3D12GraphicsCommandList2_CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box) (This)->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box)
+#define ID3D12GraphicsCommandList2_CopyResource(This,dst_resource,src_resource) (This)->lpVtbl->CopyResource(This,dst_resource,src_resource)
+#define ID3D12GraphicsCommandList2_CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags) (This)->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags)
+#define ID3D12GraphicsCommandList2_ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format) (This)->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format)
+#define ID3D12GraphicsCommandList2_IASetPrimitiveTopology(This,primitive_topology) (This)->lpVtbl->IASetPrimitiveTopology(This,primitive_topology)
+#define ID3D12GraphicsCommandList2_RSSetViewports(This,viewport_count,viewports) (This)->lpVtbl->RSSetViewports(This,viewport_count,viewports)
+#define ID3D12GraphicsCommandList2_RSSetScissorRects(This,rect_count,rects) (This)->lpVtbl->RSSetScissorRects(This,rect_count,rects)
+#define ID3D12GraphicsCommandList2_OMSetBlendFactor(This,blend_factor) (This)->lpVtbl->OMSetBlendFactor(This,blend_factor)
+#define ID3D12GraphicsCommandList2_OMSetStencilRef(This,stencil_ref) (This)->lpVtbl->OMSetStencilRef(This,stencil_ref)
+#define ID3D12GraphicsCommandList2_SetPipelineState(This,pipeline_state) (This)->lpVtbl->SetPipelineState(This,pipeline_state)
+#define ID3D12GraphicsCommandList2_ResourceBarrier(This,barrier_count,barriers) (This)->lpVtbl->ResourceBarrier(This,barrier_count,barriers)
+#define ID3D12GraphicsCommandList2_ExecuteBundle(This,command_list) (This)->lpVtbl->ExecuteBundle(This,command_list)
+#define ID3D12GraphicsCommandList2_SetDescriptorHeaps(This,heap_count,heaps) (This)->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps)
+#define ID3D12GraphicsCommandList2_SetComputeRootSignature(This,root_signature) (This)->lpVtbl->SetComputeRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList2_SetGraphicsRootSignature(This,root_signature) (This)->lpVtbl->SetGraphicsRootSignature(This,root_signature)
+#define ID3D12GraphicsCommandList2_SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList2_SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor) (This)->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor)
+#define ID3D12GraphicsCommandList2_SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList2_SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset)
+#define ID3D12GraphicsCommandList2_SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList2_SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset) (This)->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset)
+#define ID3D12GraphicsCommandList2_SetComputeRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_SetGraphicsRootConstantBufferView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_SetComputeRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_SetGraphicsRootShaderResourceView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_SetComputeRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address) (This)->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address)
+#define ID3D12GraphicsCommandList2_IASetIndexBuffer(This,view) (This)->lpVtbl->IASetIndexBuffer(This,view)
+#define ID3D12GraphicsCommandList2_IASetVertexBuffers(This,start_slot,view_count,views) (This)->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList2_SOSetTargets(This,start_slot,view_count,views) (This)->lpVtbl->SOSetTargets(This,start_slot,view_count,views)
+#define ID3D12GraphicsCommandList2_OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor) (This)->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor)
+#define ID3D12GraphicsCommandList2_ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects) (This)->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects)
+#define ID3D12GraphicsCommandList2_ClearRenderTargetView(This,rtv,color,rect_count,rects) (This)->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects)
+#define ID3D12GraphicsCommandList2_ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList2_ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects) (This)->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects)
+#define ID3D12GraphicsCommandList2_DiscardResource(This,resource,region) (This)->lpVtbl->DiscardResource(This,resource,region)
+#define ID3D12GraphicsCommandList2_BeginQuery(This,heap,type,index) (This)->lpVtbl->BeginQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList2_EndQuery(This,heap,type,index) (This)->lpVtbl->EndQuery(This,heap,type,index)
+#define ID3D12GraphicsCommandList2_ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset) (This)->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset)
+#define ID3D12GraphicsCommandList2_SetPredication(This,buffer,aligned_buffer_offset,operation) (This)->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation)
+#define ID3D12GraphicsCommandList2_SetMarker(This,metadata,data,size) (This)->lpVtbl->SetMarker(This,metadata,data,size)
+#define ID3D12GraphicsCommandList2_BeginEvent(This,metadata,data,size) (This)->lpVtbl->BeginEvent(This,metadata,data,size)
+#define ID3D12GraphicsCommandList2_EndEvent(This) (This)->lpVtbl->EndEvent(This)
+#define ID3D12GraphicsCommandList2_ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset) (This)->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset)
+/*** ID3D12GraphicsCommandList1 methods ***/
+#define ID3D12GraphicsCommandList2_AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges) (This)->lpVtbl->AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges)
+#define ID3D12GraphicsCommandList2_AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges) (This)->lpVtbl->AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges)
+#define ID3D12GraphicsCommandList2_OMSetDepthBounds(This,min,max) (This)->lpVtbl->OMSetDepthBounds(This,min,max)
+#define ID3D12GraphicsCommandList2_SetSamplePositions(This,sample_count,pixel_count,sample_positions) (This)->lpVtbl->SetSamplePositions(This,sample_count,pixel_count,sample_positions)
+#define ID3D12GraphicsCommandList2_ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode) (This)->lpVtbl->ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode)
+#define ID3D12GraphicsCommandList2_SetViewInstanceMask(This,mask) (This)->lpVtbl->SetViewInstanceMask(This,mask)
+/*** ID3D12GraphicsCommandList2 methods ***/
+#define ID3D12GraphicsCommandList2_WriteBufferImmediate(This,count,parameters,modes) (This)->lpVtbl->WriteBufferImmediate(This,count,parameters,modes)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_QueryInterface(ID3D12GraphicsCommandList2* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList2_AddRef(ID3D12GraphicsCommandList2* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12GraphicsCommandList2_Release(ID3D12GraphicsCommandList2* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_GetPrivateData(ID3D12GraphicsCommandList2* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_SetPrivateData(ID3D12GraphicsCommandList2* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_SetPrivateDataInterface(ID3D12GraphicsCommandList2* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_SetName(ID3D12GraphicsCommandList2* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_GetDevice(ID3D12GraphicsCommandList2* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandList methods ***/
+static FORCEINLINE D3D12_COMMAND_LIST_TYPE ID3D12GraphicsCommandList2_GetType(ID3D12GraphicsCommandList2* This) {
+    return This->lpVtbl->GetType(This);
+}
+/*** ID3D12GraphicsCommandList methods ***/
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_Close(ID3D12GraphicsCommandList2* This) {
+    return This->lpVtbl->Close(This);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_Reset(ID3D12GraphicsCommandList2* This,ID3D12CommandAllocator *allocator,ID3D12PipelineState *initial_state) {
+    return This->lpVtbl->Reset(This,allocator,initial_state);
+}
+static FORCEINLINE HRESULT ID3D12GraphicsCommandList2_ClearState(ID3D12GraphicsCommandList2* This,ID3D12PipelineState *pipeline_state) {
+    return This->lpVtbl->ClearState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_DrawInstanced(ID3D12GraphicsCommandList2* This,UINT vertex_count_per_instance,UINT instance_count,UINT start_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawInstanced(This,vertex_count_per_instance,instance_count,start_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_DrawIndexedInstanced(ID3D12GraphicsCommandList2* This,UINT index_count_per_instance,UINT instance_count,UINT start_vertex_location,INT base_vertex_location,UINT start_instance_location) {
+    This->lpVtbl->DrawIndexedInstanced(This,index_count_per_instance,instance_count,start_vertex_location,base_vertex_location,start_instance_location);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_Dispatch(ID3D12GraphicsCommandList2* This,UINT x,UINT u,UINT z) {
+    This->lpVtbl->Dispatch(This,x,u,z);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_CopyBufferRegion(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT64 byte_count) {
+    This->lpVtbl->CopyBufferRegion(This,dst_buffer,dst_offset,src_buffer,src_offset,byte_count);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_CopyTextureRegion(ID3D12GraphicsCommandList2* This,const D3D12_TEXTURE_COPY_LOCATION *dst,UINT dst_x,UINT dst_y,UINT dst_z,const D3D12_TEXTURE_COPY_LOCATION *src,const D3D12_BOX *src_box) {
+    This->lpVtbl->CopyTextureRegion(This,dst,dst_x,dst_y,dst_z,src,src_box);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_CopyResource(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_resource,ID3D12Resource *src_resource) {
+    This->lpVtbl->CopyResource(This,dst_resource,src_resource);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_CopyTiles(ID3D12GraphicsCommandList2* This,ID3D12Resource *tiled_resource,const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,const D3D12_TILE_REGION_SIZE *tile_region_size,ID3D12Resource *buffer,UINT64 buffer_offset,D3D12_TILE_COPY_FLAGS flags) {
+    This->lpVtbl->CopyTiles(This,tiled_resource,tile_region_start_coordinate,tile_region_size,buffer,buffer_offset,flags);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ResolveSubresource(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_resource,UINT dst_sub_resource,ID3D12Resource *src_resource,UINT src_sub_resource,DXGI_FORMAT format) {
+    This->lpVtbl->ResolveSubresource(This,dst_resource,dst_sub_resource,src_resource,src_sub_resource,format);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_IASetPrimitiveTopology(ID3D12GraphicsCommandList2* This,D3D12_PRIMITIVE_TOPOLOGY primitive_topology) {
+    This->lpVtbl->IASetPrimitiveTopology(This,primitive_topology);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_RSSetViewports(ID3D12GraphicsCommandList2* This,UINT viewport_count,const D3D12_VIEWPORT *viewports) {
+    This->lpVtbl->RSSetViewports(This,viewport_count,viewports);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_RSSetScissorRects(ID3D12GraphicsCommandList2* This,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->RSSetScissorRects(This,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_OMSetBlendFactor(ID3D12GraphicsCommandList2* This,const FLOAT blend_factor[4]) {
+    This->lpVtbl->OMSetBlendFactor(This,blend_factor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_OMSetStencilRef(ID3D12GraphicsCommandList2* This,UINT stencil_ref) {
+    This->lpVtbl->OMSetStencilRef(This,stencil_ref);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetPipelineState(ID3D12GraphicsCommandList2* This,ID3D12PipelineState *pipeline_state) {
+    This->lpVtbl->SetPipelineState(This,pipeline_state);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ResourceBarrier(ID3D12GraphicsCommandList2* This,UINT barrier_count,const D3D12_RESOURCE_BARRIER *barriers) {
+    This->lpVtbl->ResourceBarrier(This,barrier_count,barriers);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ExecuteBundle(ID3D12GraphicsCommandList2* This,ID3D12GraphicsCommandList *command_list) {
+    This->lpVtbl->ExecuteBundle(This,command_list);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetDescriptorHeaps(ID3D12GraphicsCommandList2* This,UINT heap_count,ID3D12DescriptorHeap *const *heaps) {
+    This->lpVtbl->SetDescriptorHeaps(This,heap_count,heaps);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRootSignature(ID3D12GraphicsCommandList2* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetComputeRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRootSignature(ID3D12GraphicsCommandList2* This,ID3D12RootSignature *root_signature) {
+    This->lpVtbl->SetGraphicsRootSignature(This,root_signature);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetComputeRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
+    This->lpVtbl->SetGraphicsRootDescriptorTable(This,root_parameter_index,base_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,UINT data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstant(This,root_parameter_index,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetComputeRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,UINT constant_count,const void *data,UINT dst_offset) {
+    This->lpVtbl->SetGraphicsRoot32BitConstants(This,root_parameter_index,constant_count,data,dst_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRootConstantBufferView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRootConstantBufferView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootConstantBufferView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRootShaderResourceView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRootShaderResourceView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootShaderResourceView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetComputeRootUnorderedAccessView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetComputeRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetGraphicsRootUnorderedAccessView(ID3D12GraphicsCommandList2* This,UINT root_parameter_index,D3D12_GPU_VIRTUAL_ADDRESS address) {
+    This->lpVtbl->SetGraphicsRootUnorderedAccessView(This,root_parameter_index,address);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_IASetIndexBuffer(ID3D12GraphicsCommandList2* This,const D3D12_INDEX_BUFFER_VIEW *view) {
+    This->lpVtbl->IASetIndexBuffer(This,view);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_IASetVertexBuffers(ID3D12GraphicsCommandList2* This,UINT start_slot,UINT view_count,const D3D12_VERTEX_BUFFER_VIEW *views) {
+    This->lpVtbl->IASetVertexBuffers(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SOSetTargets(ID3D12GraphicsCommandList2* This,UINT start_slot,UINT view_count,const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) {
+    This->lpVtbl->SOSetTargets(This,start_slot,view_count,views);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_OMSetRenderTargets(ID3D12GraphicsCommandList2* This,UINT render_target_descriptor_count,const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,BOOL single_descriptor_handle,const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
+    This->lpVtbl->OMSetRenderTargets(This,render_target_descriptor_count,render_target_descriptors,single_descriptor_handle,depth_stencil_descriptor);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ClearDepthStencilView(ID3D12GraphicsCommandList2* This,D3D12_CPU_DESCRIPTOR_HANDLE dsv,D3D12_CLEAR_FLAGS flags,FLOAT depth,UINT8 stencil,UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearDepthStencilView(This,dsv,flags,depth,stencil,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ClearRenderTargetView(ID3D12GraphicsCommandList2* This,D3D12_CPU_DESCRIPTOR_HANDLE rtv,const FLOAT color[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearRenderTargetView(This,rtv,color,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList2* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const UINT values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewUint(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList2* This,D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle,ID3D12Resource *resource,const float values[4],UINT rect_count,const D3D12_RECT *rects) {
+    This->lpVtbl->ClearUnorderedAccessViewFloat(This,gpu_handle,cpu_handle,resource,values,rect_count,rects);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_DiscardResource(ID3D12GraphicsCommandList2* This,ID3D12Resource *resource,const D3D12_DISCARD_REGION *region) {
+    This->lpVtbl->DiscardResource(This,resource,region);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_BeginQuery(ID3D12GraphicsCommandList2* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->BeginQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_EndQuery(ID3D12GraphicsCommandList2* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT index) {
+    This->lpVtbl->EndQuery(This,heap,type,index);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ResolveQueryData(ID3D12GraphicsCommandList2* This,ID3D12QueryHeap *heap,D3D12_QUERY_TYPE type,UINT start_index,UINT query_count,ID3D12Resource *dst_buffer,UINT64 aligned_dst_buffer_offset) {
+    This->lpVtbl->ResolveQueryData(This,heap,type,start_index,query_count,dst_buffer,aligned_dst_buffer_offset);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetPredication(ID3D12GraphicsCommandList2* This,ID3D12Resource *buffer,UINT64 aligned_buffer_offset,D3D12_PREDICATION_OP operation) {
+    This->lpVtbl->SetPredication(This,buffer,aligned_buffer_offset,operation);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetMarker(ID3D12GraphicsCommandList2* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->SetMarker(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_BeginEvent(ID3D12GraphicsCommandList2* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->BeginEvent(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_EndEvent(ID3D12GraphicsCommandList2* This) {
+    This->lpVtbl->EndEvent(This);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ExecuteIndirect(ID3D12GraphicsCommandList2* This,ID3D12CommandSignature *command_signature,UINT max_command_count,ID3D12Resource *arg_buffer,UINT64 arg_buffer_offset,ID3D12Resource *count_buffer,UINT64 count_buffer_offset) {
+    This->lpVtbl->ExecuteIndirect(This,command_signature,max_command_count,arg_buffer,arg_buffer_offset,count_buffer,count_buffer_offset);
+}
+/*** ID3D12GraphicsCommandList1 methods ***/
+static FORCEINLINE void ID3D12GraphicsCommandList2_AtomicCopyBufferUINT(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT dependent_resource_count,ID3D12Resource *const *dependent_resources,const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
+    This->lpVtbl->AtomicCopyBufferUINT(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_buffer,UINT64 dst_offset,ID3D12Resource *src_buffer,UINT64 src_offset,UINT dependent_resource_count,ID3D12Resource *const *dependent_resources,const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
+    This->lpVtbl->AtomicCopyBufferUINT64(This,dst_buffer,dst_offset,src_buffer,src_offset,dependent_resource_count,dependent_resources,dependent_sub_resource_ranges);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_OMSetDepthBounds(ID3D12GraphicsCommandList2* This,FLOAT min,FLOAT max) {
+    This->lpVtbl->OMSetDepthBounds(This,min,max);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetSamplePositions(ID3D12GraphicsCommandList2* This,UINT sample_count,UINT pixel_count,D3D12_SAMPLE_POSITION *sample_positions) {
+    This->lpVtbl->SetSamplePositions(This,sample_count,pixel_count,sample_positions);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_ResolveSubresourceRegion(ID3D12GraphicsCommandList2* This,ID3D12Resource *dst_resource,UINT dst_sub_resource_idx,UINT dst_x,UINT dst_y,ID3D12Resource *src_resource,UINT src_sub_resource_idx,D3D12_RECT *src_rect,DXGI_FORMAT format,D3D12_RESOLVE_MODE mode) {
+    This->lpVtbl->ResolveSubresourceRegion(This,dst_resource,dst_sub_resource_idx,dst_x,dst_y,src_resource,src_sub_resource_idx,src_rect,format,mode);
+}
+static FORCEINLINE void ID3D12GraphicsCommandList2_SetViewInstanceMask(ID3D12GraphicsCommandList2* This,UINT mask) {
+    This->lpVtbl->SetViewInstanceMask(This,mask);
+}
+/*** ID3D12GraphicsCommandList2 methods ***/
+static FORCEINLINE void ID3D12GraphicsCommandList2_WriteBufferImmediate(ID3D12GraphicsCommandList2* This,UINT count,const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters,const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) {
+    This->lpVtbl->WriteBufferImmediate(This,count,parameters,modes);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12GraphicsCommandList2_INTERFACE_DEFINED__ */
+
+typedef enum D3D12_TILE_RANGE_FLAGS {
+    D3D12_TILE_RANGE_FLAG_NONE = 0x0,
+    D3D12_TILE_RANGE_FLAG_NULL = 0x1,
+    D3D12_TILE_RANGE_FLAG_SKIP = 0x2,
+    D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE = 0x4
+} D3D12_TILE_RANGE_FLAGS;
+typedef enum D3D12_TILE_MAPPING_FLAGS {
+    D3D12_TILE_MAPPING_FLAG_NONE = 0x0,
+    D3D12_TILE_MAPPING_FLAG_NO_HAZARD = 0x1
+} D3D12_TILE_MAPPING_FLAGS;
+/*****************************************************************************
+ * ID3D12CommandQueue interface
+ */
+#ifndef __ID3D12CommandQueue_INTERFACE_DEFINED__
+#define __ID3D12CommandQueue_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12CommandQueue, 0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("0ec870a6-5d7e-4c22-8cfc-5baae07616ed")
+ID3D12CommandQueue : public ID3D12Pageable
+{
+    virtual void STDMETHODCALLTYPE UpdateTileMappings(
+        ID3D12Resource *resource,
+        UINT region_count,
+        const D3D12_TILED_RESOURCE_COORDINATE *region_start_coordinates,
+        const D3D12_TILE_REGION_SIZE *region_sizes,
+        UINT range_count,
+        const D3D12_TILE_RANGE_FLAGS *range_flags,
+        UINT *heap_range_offsets,
+        UINT *range_tile_counts,
+        D3D12_TILE_MAPPING_FLAGS flags) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyTileMappings(
+        ID3D12Resource *dst_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate,
+        ID3D12Resource *src_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *region_size,
+        D3D12_TILE_MAPPING_FLAGS flags) = 0;
+
+    virtual void STDMETHODCALLTYPE ExecuteCommandLists(
+        UINT command_list_count,
+        ID3D12CommandList *const *command_lists) = 0;
+
+    virtual void STDMETHODCALLTYPE SetMarker(
+        UINT metadata,
+        const void *data,
+        UINT size) = 0;
+
+    virtual void STDMETHODCALLTYPE BeginEvent(
+        UINT metadata,
+        const void *data,
+        UINT size) = 0;
+
+    virtual void STDMETHODCALLTYPE EndEvent(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Signal(
+        ID3D12Fence *fence,
+        UINT64 value) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Wait(
+        ID3D12Fence *fence,
+        UINT64 value) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetTimestampFrequency(
+        UINT64 *frequency) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetClockCalibration(
+        UINT64 *gpu_timestamp,
+        UINT64 *cpu_timestamp) = 0;
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_COMMAND_QUEUE_DESC* STDMETHODCALLTYPE GetDesc(
+        D3D12_COMMAND_QUEUE_DESC *__ret) = 0;
+    D3D12_COMMAND_QUEUE_DESC STDMETHODCALLTYPE GetDesc(
+        )
+    {
+        D3D12_COMMAND_QUEUE_DESC __ret;
+        return *GetDesc(&__ret);
+    }
+#else
+    virtual D3D12_COMMAND_QUEUE_DESC STDMETHODCALLTYPE GetDesc(
+        ) = 0;
+#endif
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12CommandQueue, 0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed)
+#endif
+#else
+typedef struct ID3D12CommandQueueVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12CommandQueue *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12CommandQueue *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12CommandQueue *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12CommandQueue *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12CommandQueue *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12CommandQueue *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12CommandQueue *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12CommandQueue *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandQueue methods ***/
+    void (STDMETHODCALLTYPE *UpdateTileMappings)(
+        ID3D12CommandQueue *This,
+        ID3D12Resource *resource,
+        UINT region_count,
+        const D3D12_TILED_RESOURCE_COORDINATE *region_start_coordinates,
+        const D3D12_TILE_REGION_SIZE *region_sizes,
+        UINT range_count,
+        const D3D12_TILE_RANGE_FLAGS *range_flags,
+        UINT *heap_range_offsets,
+        UINT *range_tile_counts,
+        D3D12_TILE_MAPPING_FLAGS flags);
+
+    void (STDMETHODCALLTYPE *CopyTileMappings)(
+        ID3D12CommandQueue *This,
+        ID3D12Resource *dst_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate,
+        ID3D12Resource *src_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *region_size,
+        D3D12_TILE_MAPPING_FLAGS flags);
+
+    void (STDMETHODCALLTYPE *ExecuteCommandLists)(
+        ID3D12CommandQueue *This,
+        UINT command_list_count,
+        ID3D12CommandList *const *command_lists);
+
+    void (STDMETHODCALLTYPE *SetMarker)(
+        ID3D12CommandQueue *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *BeginEvent)(
+        ID3D12CommandQueue *This,
+        UINT metadata,
+        const void *data,
+        UINT size);
+
+    void (STDMETHODCALLTYPE *EndEvent)(
+        ID3D12CommandQueue *This);
+
+    HRESULT (STDMETHODCALLTYPE *Signal)(
+        ID3D12CommandQueue *This,
+        ID3D12Fence *fence,
+        UINT64 value);
+
+    HRESULT (STDMETHODCALLTYPE *Wait)(
+        ID3D12CommandQueue *This,
+        ID3D12Fence *fence,
+        UINT64 value);
+
+    HRESULT (STDMETHODCALLTYPE *GetTimestampFrequency)(
+        ID3D12CommandQueue *This,
+        UINT64 *frequency);
+
+    HRESULT (STDMETHODCALLTYPE *GetClockCalibration)(
+        ID3D12CommandQueue *This,
+        UINT64 *gpu_timestamp,
+        UINT64 *cpu_timestamp);
+
+    D3D12_COMMAND_QUEUE_DESC * (STDMETHODCALLTYPE *GetDesc)(
+        ID3D12CommandQueue *This,
+        D3D12_COMMAND_QUEUE_DESC *__ret);
+
+    END_INTERFACE
+} ID3D12CommandQueueVtbl;
+
+interface ID3D12CommandQueue {
+    CONST_VTBL ID3D12CommandQueueVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12CommandQueue_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12CommandQueue_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12CommandQueue_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12CommandQueue_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandQueue_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandQueue_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12CommandQueue_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12CommandQueue_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandQueue methods ***/
+#define ID3D12CommandQueue_UpdateTileMappings(This,resource,region_count,region_start_coordinates,region_sizes,range_count,range_flags,heap_range_offsets,range_tile_counts,flags) (This)->lpVtbl->UpdateTileMappings(This,resource,region_count,region_start_coordinates,region_sizes,range_count,range_flags,heap_range_offsets,range_tile_counts,flags)
+#define ID3D12CommandQueue_CopyTileMappings(This,dst_resource,dst_region_start_coordinate,src_resource,src_region_start_coordinate,region_size,flags) (This)->lpVtbl->CopyTileMappings(This,dst_resource,dst_region_start_coordinate,src_resource,src_region_start_coordinate,region_size,flags)
+#define ID3D12CommandQueue_ExecuteCommandLists(This,command_list_count,command_lists) (This)->lpVtbl->ExecuteCommandLists(This,command_list_count,command_lists)
+#define ID3D12CommandQueue_SetMarker(This,metadata,data,size) (This)->lpVtbl->SetMarker(This,metadata,data,size)
+#define ID3D12CommandQueue_BeginEvent(This,metadata,data,size) (This)->lpVtbl->BeginEvent(This,metadata,data,size)
+#define ID3D12CommandQueue_EndEvent(This) (This)->lpVtbl->EndEvent(This)
+#define ID3D12CommandQueue_Signal(This,fence,value) (This)->lpVtbl->Signal(This,fence,value)
+#define ID3D12CommandQueue_Wait(This,fence,value) (This)->lpVtbl->Wait(This,fence,value)
+#define ID3D12CommandQueue_GetTimestampFrequency(This,frequency) (This)->lpVtbl->GetTimestampFrequency(This,frequency)
+#define ID3D12CommandQueue_GetClockCalibration(This,gpu_timestamp,cpu_timestamp) (This)->lpVtbl->GetClockCalibration(This,gpu_timestamp,cpu_timestamp)
+#define ID3D12CommandQueue_GetDesc(This) ID3D12CommandQueue_GetDesc_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12CommandQueue_QueryInterface(ID3D12CommandQueue* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12CommandQueue_AddRef(ID3D12CommandQueue* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12CommandQueue_Release(ID3D12CommandQueue* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12CommandQueue_GetPrivateData(ID3D12CommandQueue* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_SetPrivateData(ID3D12CommandQueue* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_SetPrivateDataInterface(ID3D12CommandQueue* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_SetName(ID3D12CommandQueue* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12CommandQueue_GetDevice(ID3D12CommandQueue* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandQueue methods ***/
+static FORCEINLINE void ID3D12CommandQueue_UpdateTileMappings(ID3D12CommandQueue* This,ID3D12Resource *resource,UINT region_count,const D3D12_TILED_RESOURCE_COORDINATE *region_start_coordinates,const D3D12_TILE_REGION_SIZE *region_sizes,UINT range_count,const D3D12_TILE_RANGE_FLAGS *range_flags,UINT *heap_range_offsets,UINT *range_tile_counts,D3D12_TILE_MAPPING_FLAGS flags) {
+    This->lpVtbl->UpdateTileMappings(This,resource,region_count,region_start_coordinates,region_sizes,range_count,range_flags,heap_range_offsets,range_tile_counts,flags);
+}
+static FORCEINLINE void ID3D12CommandQueue_CopyTileMappings(ID3D12CommandQueue* This,ID3D12Resource *dst_resource,const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate,ID3D12Resource *src_resource,const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate,const D3D12_TILE_REGION_SIZE *region_size,D3D12_TILE_MAPPING_FLAGS flags) {
+    This->lpVtbl->CopyTileMappings(This,dst_resource,dst_region_start_coordinate,src_resource,src_region_start_coordinate,region_size,flags);
+}
+static FORCEINLINE void ID3D12CommandQueue_ExecuteCommandLists(ID3D12CommandQueue* This,UINT command_list_count,ID3D12CommandList *const *command_lists) {
+    This->lpVtbl->ExecuteCommandLists(This,command_list_count,command_lists);
+}
+static FORCEINLINE void ID3D12CommandQueue_SetMarker(ID3D12CommandQueue* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->SetMarker(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12CommandQueue_BeginEvent(ID3D12CommandQueue* This,UINT metadata,const void *data,UINT size) {
+    This->lpVtbl->BeginEvent(This,metadata,data,size);
+}
+static FORCEINLINE void ID3D12CommandQueue_EndEvent(ID3D12CommandQueue* This) {
+    This->lpVtbl->EndEvent(This);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_Signal(ID3D12CommandQueue* This,ID3D12Fence *fence,UINT64 value) {
+    return This->lpVtbl->Signal(This,fence,value);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_Wait(ID3D12CommandQueue* This,ID3D12Fence *fence,UINT64 value) {
+    return This->lpVtbl->Wait(This,fence,value);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_GetTimestampFrequency(ID3D12CommandQueue* This,UINT64 *frequency) {
+    return This->lpVtbl->GetTimestampFrequency(This,frequency);
+}
+static FORCEINLINE HRESULT ID3D12CommandQueue_GetClockCalibration(ID3D12CommandQueue* This,UINT64 *gpu_timestamp,UINT64 *cpu_timestamp) {
+    return This->lpVtbl->GetClockCalibration(This,gpu_timestamp,cpu_timestamp);
+}
+static FORCEINLINE D3D12_COMMAND_QUEUE_DESC ID3D12CommandQueue_GetDesc(ID3D12CommandQueue* This) {
+    D3D12_COMMAND_QUEUE_DESC __ret;
+    return *This->lpVtbl->GetDesc(This,&__ret);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12CommandQueue_INTERFACE_DEFINED__ */
+
+typedef enum D3D12_FENCE_FLAGS {
+    D3D12_FENCE_FLAG_NONE = 0x0,
+    D3D12_FENCE_FLAG_SHARED = 0x1,
+    D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER = 0x2
+} D3D12_FENCE_FLAGS;
+typedef enum D3D12_QUERY_HEAP_TYPE {
+    D3D12_QUERY_HEAP_TYPE_OCCLUSION = 0,
+    D3D12_QUERY_HEAP_TYPE_TIMESTAMP = 1,
+    D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS = 2,
+    D3D12_QUERY_HEAP_TYPE_SO_STATISTICS = 3
+} D3D12_QUERY_HEAP_TYPE;
+typedef struct D3D12_QUERY_HEAP_DESC {
+    D3D12_QUERY_HEAP_TYPE Type;
+    UINT Count;
+    UINT NodeMask;
+} D3D12_QUERY_HEAP_DESC;
+typedef enum D3D12_INDIRECT_ARGUMENT_TYPE {
+    D3D12_INDIRECT_ARGUMENT_TYPE_DRAW = 0,
+    D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED = 1,
+    D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH = 2,
+    D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW = 3,
+    D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW = 4,
+    D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT = 5,
+    D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW = 6,
+    D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW = 7,
+    D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW = 8
+} D3D12_INDIRECT_ARGUMENT_TYPE;
+typedef struct D3D12_INDIRECT_ARGUMENT_DESC {
+    D3D12_INDIRECT_ARGUMENT_TYPE Type;
+    __C89_NAMELESS union {
+        struct {
+            UINT Slot;
+        } VertexBuffer;
+        struct {
+            UINT RootParameterIndex;
+            UINT DestOffsetIn32BitValues;
+            UINT Num32BitValuesToSet;
+        } Constant;
+        struct {
+            UINT RootParameterIndex;
+        } ConstantBufferView;
+        struct {
+            UINT RootParameterIndex;
+        } ShaderResourceView;
+        struct {
+            UINT RootParameterIndex;
+        } UnorderedAccessView;
+    } __C89_NAMELESSUNIONNAME;
+} D3D12_INDIRECT_ARGUMENT_DESC;
+typedef struct D3D12_COMMAND_SIGNATURE_DESC {
+    UINT ByteStride;
+    UINT NumArgumentDescs;
+    const D3D12_INDIRECT_ARGUMENT_DESC *pArgumentDescs;
+    UINT NodeMask;
+} D3D12_COMMAND_SIGNATURE_DESC;
+/*****************************************************************************
+ * ID3D12RootSignature interface
+ */
+#ifndef __ID3D12RootSignature_INTERFACE_DEFINED__
+#define __ID3D12RootSignature_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12RootSignature, 0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("c54a6b66-72df-4ee8-8be5-a946a1429214")
+ID3D12RootSignature : public ID3D12DeviceChild
+{
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12RootSignature, 0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14)
+#endif
+#else
+typedef struct ID3D12RootSignatureVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12RootSignature *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12RootSignature *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12RootSignature *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12RootSignature *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12RootSignature *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12RootSignature *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12RootSignature *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12RootSignature *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} ID3D12RootSignatureVtbl;
+
+interface ID3D12RootSignature {
+    CONST_VTBL ID3D12RootSignatureVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12RootSignature_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12RootSignature_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12RootSignature_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12RootSignature_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12RootSignature_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12RootSignature_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12RootSignature_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12RootSignature_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12RootSignature_QueryInterface(ID3D12RootSignature* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12RootSignature_AddRef(ID3D12RootSignature* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12RootSignature_Release(ID3D12RootSignature* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12RootSignature_GetPrivateData(ID3D12RootSignature* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12RootSignature_SetPrivateData(ID3D12RootSignature* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12RootSignature_SetPrivateDataInterface(ID3D12RootSignature* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12RootSignature_SetName(ID3D12RootSignature* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12RootSignature_GetDevice(ID3D12RootSignature* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12RootSignature_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12PipelineState interface
+ */
+#ifndef __ID3D12PipelineState_INTERFACE_DEFINED__
+#define __ID3D12PipelineState_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12PipelineState, 0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("765a30f3-f624-4c6f-a828-ace948622445")
+ID3D12PipelineState : public ID3D12Pageable
+{
+    virtual HRESULT STDMETHODCALLTYPE GetCachedBlob(
+        ID3DBlob **blob) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12PipelineState, 0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45)
+#endif
+#else
+typedef struct ID3D12PipelineStateVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12PipelineState *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12PipelineState *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12PipelineState *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12PipelineState *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12PipelineState *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12PipelineState *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12PipelineState *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12PipelineState *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12PipelineState methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetCachedBlob)(
+        ID3D12PipelineState *This,
+        ID3DBlob **blob);
+
+    END_INTERFACE
+} ID3D12PipelineStateVtbl;
+
+interface ID3D12PipelineState {
+    CONST_VTBL ID3D12PipelineStateVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12PipelineState_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12PipelineState_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12PipelineState_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12PipelineState_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12PipelineState_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12PipelineState_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12PipelineState_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12PipelineState_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12PipelineState methods ***/
+#define ID3D12PipelineState_GetCachedBlob(This,blob) (This)->lpVtbl->GetCachedBlob(This,blob)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12PipelineState_QueryInterface(ID3D12PipelineState* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12PipelineState_AddRef(ID3D12PipelineState* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12PipelineState_Release(ID3D12PipelineState* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12PipelineState_GetPrivateData(ID3D12PipelineState* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12PipelineState_SetPrivateData(ID3D12PipelineState* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12PipelineState_SetPrivateDataInterface(ID3D12PipelineState* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12PipelineState_SetName(ID3D12PipelineState* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12PipelineState_GetDevice(ID3D12PipelineState* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12PipelineState methods ***/
+static FORCEINLINE HRESULT ID3D12PipelineState_GetCachedBlob(ID3D12PipelineState* This,ID3DBlob **blob) {
+    return This->lpVtbl->GetCachedBlob(This,blob);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12PipelineState_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Fence interface
+ */
+#ifndef __ID3D12Fence_INTERFACE_DEFINED__
+#define __ID3D12Fence_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Fence, 0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("0a753dcf-c4d8-4b91-adf6-be5a60d95a76")
+ID3D12Fence : public ID3D12Pageable
+{
+    virtual UINT64 STDMETHODCALLTYPE GetCompletedValue(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetEventOnCompletion(
+        UINT64 value,
+        HANDLE event) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Signal(
+        UINT64 value) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Fence, 0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76)
+#endif
+#else
+typedef struct ID3D12FenceVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Fence *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Fence *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Fence *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Fence *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Fence *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Fence *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Fence *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12Fence *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12Fence methods ***/
+    UINT64 (STDMETHODCALLTYPE *GetCompletedValue)(
+        ID3D12Fence *This);
+
+    HRESULT (STDMETHODCALLTYPE *SetEventOnCompletion)(
+        ID3D12Fence *This,
+        UINT64 value,
+        HANDLE event);
+
+    HRESULT (STDMETHODCALLTYPE *Signal)(
+        ID3D12Fence *This,
+        UINT64 value);
+
+    END_INTERFACE
+} ID3D12FenceVtbl;
+
+interface ID3D12Fence {
+    CONST_VTBL ID3D12FenceVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Fence_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Fence_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Fence_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Fence_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Fence_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Fence_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Fence_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12Fence_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12Fence methods ***/
+#define ID3D12Fence_GetCompletedValue(This) (This)->lpVtbl->GetCompletedValue(This)
+#define ID3D12Fence_SetEventOnCompletion(This,value,event) (This)->lpVtbl->SetEventOnCompletion(This,value,event)
+#define ID3D12Fence_Signal(This,value) (This)->lpVtbl->Signal(This,value)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Fence_QueryInterface(ID3D12Fence* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Fence_AddRef(ID3D12Fence* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Fence_Release(ID3D12Fence* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Fence_GetPrivateData(ID3D12Fence* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Fence_SetPrivateData(ID3D12Fence* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Fence_SetPrivateDataInterface(ID3D12Fence* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Fence_SetName(ID3D12Fence* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12Fence_GetDevice(ID3D12Fence* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12Fence methods ***/
+static FORCEINLINE UINT64 ID3D12Fence_GetCompletedValue(ID3D12Fence* This) {
+    return This->lpVtbl->GetCompletedValue(This);
+}
+static FORCEINLINE HRESULT ID3D12Fence_SetEventOnCompletion(ID3D12Fence* This,UINT64 value,HANDLE event) {
+    return This->lpVtbl->SetEventOnCompletion(This,value,event);
+}
+static FORCEINLINE HRESULT ID3D12Fence_Signal(ID3D12Fence* This,UINT64 value) {
+    return This->lpVtbl->Signal(This,value);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Fence_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12CommandAllocator interface
+ */
+#ifndef __ID3D12CommandAllocator_INTERFACE_DEFINED__
+#define __ID3D12CommandAllocator_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12CommandAllocator, 0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("6102dee4-af59-4b09-b999-b44d73f09b24")
+ID3D12CommandAllocator : public ID3D12Pageable
+{
+    virtual HRESULT STDMETHODCALLTYPE Reset(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12CommandAllocator, 0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24)
+#endif
+#else
+typedef struct ID3D12CommandAllocatorVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12CommandAllocator *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12CommandAllocator *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12CommandAllocator *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12CommandAllocator *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12CommandAllocator *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12CommandAllocator *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12CommandAllocator *This,
+        const WCHAR *name);
+
+    /*** ID3D12DeviceChild methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        ID3D12CommandAllocator *This,
+        REFIID riid,
+        void **device);
+
+    /*** ID3D12CommandAllocator methods ***/
+    HRESULT (STDMETHODCALLTYPE *Reset)(
+        ID3D12CommandAllocator *This);
+
+    END_INTERFACE
+} ID3D12CommandAllocatorVtbl;
+
+interface ID3D12CommandAllocator {
+    CONST_VTBL ID3D12CommandAllocatorVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12CommandAllocator_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12CommandAllocator_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12CommandAllocator_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12CommandAllocator_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandAllocator_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12CommandAllocator_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12CommandAllocator_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12DeviceChild methods ***/
+#define ID3D12CommandAllocator_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** ID3D12CommandAllocator methods ***/
+#define ID3D12CommandAllocator_Reset(This) (This)->lpVtbl->Reset(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12CommandAllocator_QueryInterface(ID3D12CommandAllocator* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12CommandAllocator_AddRef(ID3D12CommandAllocator* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12CommandAllocator_Release(ID3D12CommandAllocator* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12CommandAllocator_GetPrivateData(ID3D12CommandAllocator* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandAllocator_SetPrivateData(ID3D12CommandAllocator* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandAllocator_SetPrivateDataInterface(ID3D12CommandAllocator* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12CommandAllocator_SetName(ID3D12CommandAllocator* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12DeviceChild methods ***/
+static FORCEINLINE HRESULT ID3D12CommandAllocator_GetDevice(ID3D12CommandAllocator* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** ID3D12CommandAllocator methods ***/
+static FORCEINLINE HRESULT ID3D12CommandAllocator_Reset(ID3D12CommandAllocator* This) {
+    return This->lpVtbl->Reset(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12CommandAllocator_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Device interface
+ */
+#ifndef __ID3D12Device_INTERFACE_DEFINED__
+#define __ID3D12Device_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Device, 0x189819f1, 0x1db6, 0x4b57, 0xbe,0x54, 0x18,0x21,0x33,0x9b,0x85,0xf7);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("189819f1-1db6-4b57-be54-1821339b85f7")
+ID3D12Device : public ID3D12Object
+{
+    virtual UINT STDMETHODCALLTYPE GetNodeCount(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateCommandQueue(
+        const D3D12_COMMAND_QUEUE_DESC *desc,
+        REFIID riid,
+        void **command_queue) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateCommandAllocator(
+        D3D12_COMMAND_LIST_TYPE type,
+        REFIID riid,
+        void **command_allocator) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateGraphicsPipelineState(
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateComputePipelineState(
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateCommandList(
+        UINT node_mask,
+        D3D12_COMMAND_LIST_TYPE type,
+        ID3D12CommandAllocator *command_allocator,
+        ID3D12PipelineState *initial_pipeline_state,
+        REFIID riid,
+        void **command_list) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CheckFeatureSupport(
+        D3D12_FEATURE feature,
+        void *feature_data,
+        UINT feature_data_size) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateDescriptorHeap(
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc,
+        REFIID riid,
+        void **descriptor_heap) = 0;
+
+    virtual UINT STDMETHODCALLTYPE GetDescriptorHandleIncrementSize(
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateRootSignature(
+        UINT node_mask,
+        const void *bytecode,
+        SIZE_T bytecode_length,
+        REFIID riid,
+        void **root_signature) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateConstantBufferView(
+        const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateShaderResourceView(
+        ID3D12Resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateUnorderedAccessView(
+        ID3D12Resource *resource,
+        ID3D12Resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateRenderTargetView(
+        ID3D12Resource *resource,
+        const D3D12_RENDER_TARGET_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateDepthStencilView(
+        ID3D12Resource *resource,
+        const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CreateSampler(
+        const D3D12_SAMPLER_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyDescriptors(
+        UINT dst_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
+        const UINT *dst_descriptor_range_sizes,
+        UINT src_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
+        const UINT *src_descriptor_range_sizes,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) = 0;
+
+    virtual void STDMETHODCALLTYPE CopyDescriptorsSimple(
+        UINT descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
+        const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) = 0;
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_RESOURCE_ALLOCATION_INFO* STDMETHODCALLTYPE GetResourceAllocationInfo(
+        D3D12_RESOURCE_ALLOCATION_INFO *__ret,
+        UINT visible_mask,
+        UINT reource_desc_count,
+        const D3D12_RESOURCE_DESC *resource_descs) = 0;
+    D3D12_RESOURCE_ALLOCATION_INFO STDMETHODCALLTYPE GetResourceAllocationInfo(
+        UINT visible_mask,
+        UINT reource_desc_count,
+        const D3D12_RESOURCE_DESC *resource_descs)
+    {
+        D3D12_RESOURCE_ALLOCATION_INFO __ret;
+        return *GetResourceAllocationInfo(&__ret, visible_mask, reource_desc_count, resource_descs);
+    }
+#else
+    virtual D3D12_RESOURCE_ALLOCATION_INFO STDMETHODCALLTYPE GetResourceAllocationInfo(
+        UINT visible_mask,
+        UINT reource_desc_count,
+        const D3D12_RESOURCE_DESC *resource_descs) = 0;
+#endif
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual D3D12_HEAP_PROPERTIES* STDMETHODCALLTYPE GetCustomHeapProperties(
+        D3D12_HEAP_PROPERTIES *__ret,
+        UINT node_mask,
+        D3D12_HEAP_TYPE heap_type) = 0;
+    D3D12_HEAP_PROPERTIES STDMETHODCALLTYPE GetCustomHeapProperties(
+        UINT node_mask,
+        D3D12_HEAP_TYPE heap_type)
+    {
+        D3D12_HEAP_PROPERTIES __ret;
+        return *GetCustomHeapProperties(&__ret, node_mask, heap_type);
+    }
+#else
+    virtual D3D12_HEAP_PROPERTIES STDMETHODCALLTYPE GetCustomHeapProperties(
+        UINT node_mask,
+        D3D12_HEAP_TYPE heap_type) = 0;
+#endif
+
+    virtual HRESULT STDMETHODCALLTYPE CreateCommittedResource(
+        const D3D12_HEAP_PROPERTIES *heap_properties,
+        D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateHeap(
+        const D3D12_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreatePlacedResource(
+        ID3D12Heap *heap,
+        UINT64 heap_offset,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateReservedResource(
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSharedHandle(
+        ID3D12DeviceChild *object,
+        const SECURITY_ATTRIBUTES *attributes,
+        DWORD access,
+        const WCHAR *name,
+        HANDLE *handle) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE OpenSharedHandle(
+        HANDLE handle,
+        REFIID riid,
+        void **object) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE OpenSharedHandleByName(
+        const WCHAR *name,
+        DWORD access,
+        HANDLE *handle) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE MakeResident(
+        UINT object_count,
+        ID3D12Pageable *const *objects) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Evict(
+        UINT object_count,
+        ID3D12Pageable *const *objects) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateFence(
+        UINT64 initial_value,
+        D3D12_FENCE_FLAGS flags,
+        REFIID riid,
+        void **fence) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason(
+        ) = 0;
+
+    virtual void STDMETHODCALLTYPE GetCopyableFootprints(
+        const D3D12_RESOURCE_DESC *desc,
+        UINT first_sub_resource,
+        UINT sub_resource_count,
+        UINT64 base_offset,
+        D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
+        UINT *row_count,
+        UINT64 *row_size,
+        UINT64 *total_bytes) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateQueryHeap(
+        const D3D12_QUERY_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetStablePowerState(
+        BOOL enable) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateCommandSignature(
+        const D3D12_COMMAND_SIGNATURE_DESC *desc,
+        ID3D12RootSignature *root_signature,
+        REFIID riid,
+        void **command_signature) = 0;
+
+    virtual void STDMETHODCALLTYPE GetResourceTiling(
+        ID3D12Resource *resource,
+        UINT *total_tile_count,
+        D3D12_PACKED_MIP_INFO *packed_mip_info,
+        D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *sub_resource_tiling_count,
+        UINT first_sub_resource_tiling,
+        D3D12_SUBRESOURCE_TILING *sub_resource_tilings) = 0;
+
+#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS
+    virtual LUID* STDMETHODCALLTYPE GetAdapterLuid(
+        LUID *__ret) = 0;
+    LUID STDMETHODCALLTYPE GetAdapterLuid(
+        )
+    {
+        LUID __ret;
+        return *GetAdapterLuid(&__ret);
+    }
+#else
+    virtual LUID STDMETHODCALLTYPE GetAdapterLuid(
+        ) = 0;
+#endif
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Device, 0x189819f1, 0x1db6, 0x4b57, 0xbe,0x54, 0x18,0x21,0x33,0x9b,0x85,0xf7)
+#endif
+#else
+typedef struct ID3D12DeviceVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Device *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Device *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Device *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Device *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Device *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Device *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Device *This,
+        const WCHAR *name);
+
+    /*** ID3D12Device methods ***/
+    UINT (STDMETHODCALLTYPE *GetNodeCount)(
+        ID3D12Device *This);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandQueue)(
+        ID3D12Device *This,
+        const D3D12_COMMAND_QUEUE_DESC *desc,
+        REFIID riid,
+        void **command_queue);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandAllocator)(
+        ID3D12Device *This,
+        D3D12_COMMAND_LIST_TYPE type,
+        REFIID riid,
+        void **command_allocator);
+
+    HRESULT (STDMETHODCALLTYPE *CreateGraphicsPipelineState)(
+        ID3D12Device *This,
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state);
+
+    HRESULT (STDMETHODCALLTYPE *CreateComputePipelineState)(
+        ID3D12Device *This,
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandList)(
+        ID3D12Device *This,
+        UINT node_mask,
+        D3D12_COMMAND_LIST_TYPE type,
+        ID3D12CommandAllocator *command_allocator,
+        ID3D12PipelineState *initial_pipeline_state,
+        REFIID riid,
+        void **command_list);
+
+    HRESULT (STDMETHODCALLTYPE *CheckFeatureSupport)(
+        ID3D12Device *This,
+        D3D12_FEATURE feature,
+        void *feature_data,
+        UINT feature_data_size);
+
+    HRESULT (STDMETHODCALLTYPE *CreateDescriptorHeap)(
+        ID3D12Device *This,
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc,
+        REFIID riid,
+        void **descriptor_heap);
+
+    UINT (STDMETHODCALLTYPE *GetDescriptorHandleIncrementSize)(
+        ID3D12Device *This,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    HRESULT (STDMETHODCALLTYPE *CreateRootSignature)(
+        ID3D12Device *This,
+        UINT node_mask,
+        const void *bytecode,
+        SIZE_T bytecode_length,
+        REFIID riid,
+        void **root_signature);
+
+    void (STDMETHODCALLTYPE *CreateConstantBufferView)(
+        ID3D12Device *This,
+        const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateShaderResourceView)(
+        ID3D12Device *This,
+        ID3D12Resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateUnorderedAccessView)(
+        ID3D12Device *This,
+        ID3D12Resource *resource,
+        ID3D12Resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateRenderTargetView)(
+        ID3D12Device *This,
+        ID3D12Resource *resource,
+        const D3D12_RENDER_TARGET_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateDepthStencilView)(
+        ID3D12Device *This,
+        ID3D12Resource *resource,
+        const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateSampler)(
+        ID3D12Device *This,
+        const D3D12_SAMPLER_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CopyDescriptors)(
+        ID3D12Device *This,
+        UINT dst_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
+        const UINT *dst_descriptor_range_sizes,
+        UINT src_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
+        const UINT *src_descriptor_range_sizes,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    void (STDMETHODCALLTYPE *CopyDescriptorsSimple)(
+        ID3D12Device *This,
+        UINT descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
+        const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    D3D12_RESOURCE_ALLOCATION_INFO * (STDMETHODCALLTYPE *GetResourceAllocationInfo)(
+        ID3D12Device *This,
+        D3D12_RESOURCE_ALLOCATION_INFO *__ret,
+        UINT visible_mask,
+        UINT reource_desc_count,
+        const D3D12_RESOURCE_DESC *resource_descs);
+
+    D3D12_HEAP_PROPERTIES * (STDMETHODCALLTYPE *GetCustomHeapProperties)(
+        ID3D12Device *This,
+        D3D12_HEAP_PROPERTIES *__ret,
+        UINT node_mask,
+        D3D12_HEAP_TYPE heap_type);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommittedResource)(
+        ID3D12Device *This,
+        const D3D12_HEAP_PROPERTIES *heap_properties,
+        D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateHeap)(
+        ID3D12Device *This,
+        const D3D12_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap);
+
+    HRESULT (STDMETHODCALLTYPE *CreatePlacedResource)(
+        ID3D12Device *This,
+        ID3D12Heap *heap,
+        UINT64 heap_offset,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateReservedResource)(
+        ID3D12Device *This,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSharedHandle)(
+        ID3D12Device *This,
+        ID3D12DeviceChild *object,
+        const SECURITY_ATTRIBUTES *attributes,
+        DWORD access,
+        const WCHAR *name,
+        HANDLE *handle);
+
+    HRESULT (STDMETHODCALLTYPE *OpenSharedHandle)(
+        ID3D12Device *This,
+        HANDLE handle,
+        REFIID riid,
+        void **object);
+
+    HRESULT (STDMETHODCALLTYPE *OpenSharedHandleByName)(
+        ID3D12Device *This,
+        const WCHAR *name,
+        DWORD access,
+        HANDLE *handle);
+
+    HRESULT (STDMETHODCALLTYPE *MakeResident)(
+        ID3D12Device *This,
+        UINT object_count,
+        ID3D12Pageable *const *objects);
+
+    HRESULT (STDMETHODCALLTYPE *Evict)(
+        ID3D12Device *This,
+        UINT object_count,
+        ID3D12Pageable *const *objects);
+
+    HRESULT (STDMETHODCALLTYPE *CreateFence)(
+        ID3D12Device *This,
+        UINT64 initial_value,
+        D3D12_FENCE_FLAGS flags,
+        REFIID riid,
+        void **fence);
+
+    HRESULT (STDMETHODCALLTYPE *GetDeviceRemovedReason)(
+        ID3D12Device *This);
+
+    void (STDMETHODCALLTYPE *GetCopyableFootprints)(
+        ID3D12Device *This,
+        const D3D12_RESOURCE_DESC *desc,
+        UINT first_sub_resource,
+        UINT sub_resource_count,
+        UINT64 base_offset,
+        D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
+        UINT *row_count,
+        UINT64 *row_size,
+        UINT64 *total_bytes);
+
+    HRESULT (STDMETHODCALLTYPE *CreateQueryHeap)(
+        ID3D12Device *This,
+        const D3D12_QUERY_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap);
+
+    HRESULT (STDMETHODCALLTYPE *SetStablePowerState)(
+        ID3D12Device *This,
+        BOOL enable);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandSignature)(
+        ID3D12Device *This,
+        const D3D12_COMMAND_SIGNATURE_DESC *desc,
+        ID3D12RootSignature *root_signature,
+        REFIID riid,
+        void **command_signature);
+
+    void (STDMETHODCALLTYPE *GetResourceTiling)(
+        ID3D12Device *This,
+        ID3D12Resource *resource,
+        UINT *total_tile_count,
+        D3D12_PACKED_MIP_INFO *packed_mip_info,
+        D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *sub_resource_tiling_count,
+        UINT first_sub_resource_tiling,
+        D3D12_SUBRESOURCE_TILING *sub_resource_tilings);
+
+    LUID * (STDMETHODCALLTYPE *GetAdapterLuid)(
+        ID3D12Device *This,
+        LUID *__ret);
+
+    END_INTERFACE
+} ID3D12DeviceVtbl;
+
+interface ID3D12Device {
+    CONST_VTBL ID3D12DeviceVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Device_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Device_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Device_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Device_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Device_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Device_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Device_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12Device methods ***/
+#define ID3D12Device_GetNodeCount(This) (This)->lpVtbl->GetNodeCount(This)
+#define ID3D12Device_CreateCommandQueue(This,desc,riid,command_queue) (This)->lpVtbl->CreateCommandQueue(This,desc,riid,command_queue)
+#define ID3D12Device_CreateCommandAllocator(This,type,riid,command_allocator) (This)->lpVtbl->CreateCommandAllocator(This,type,riid,command_allocator)
+#define ID3D12Device_CreateGraphicsPipelineState(This,desc,riid,pipeline_state) (This)->lpVtbl->CreateGraphicsPipelineState(This,desc,riid,pipeline_state)
+#define ID3D12Device_CreateComputePipelineState(This,desc,riid,pipeline_state) (This)->lpVtbl->CreateComputePipelineState(This,desc,riid,pipeline_state)
+#define ID3D12Device_CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list) (This)->lpVtbl->CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list)
+#define ID3D12Device_CheckFeatureSupport(This,feature,feature_data,feature_data_size) (This)->lpVtbl->CheckFeatureSupport(This,feature,feature_data,feature_data_size)
+#define ID3D12Device_CreateDescriptorHeap(This,desc,riid,descriptor_heap) (This)->lpVtbl->CreateDescriptorHeap(This,desc,riid,descriptor_heap)
+#define ID3D12Device_GetDescriptorHandleIncrementSize(This,descriptor_heap_type) (This)->lpVtbl->GetDescriptorHandleIncrementSize(This,descriptor_heap_type)
+#define ID3D12Device_CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature) (This)->lpVtbl->CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature)
+#define ID3D12Device_CreateConstantBufferView(This,desc,descriptor) (This)->lpVtbl->CreateConstantBufferView(This,desc,descriptor)
+#define ID3D12Device_CreateShaderResourceView(This,resource,desc,descriptor) (This)->lpVtbl->CreateShaderResourceView(This,resource,desc,descriptor)
+#define ID3D12Device_CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor) (This)->lpVtbl->CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor)
+#define ID3D12Device_CreateRenderTargetView(This,resource,desc,descriptor) (This)->lpVtbl->CreateRenderTargetView(This,resource,desc,descriptor)
+#define ID3D12Device_CreateDepthStencilView(This,resource,desc,descriptor) (This)->lpVtbl->CreateDepthStencilView(This,resource,desc,descriptor)
+#define ID3D12Device_CreateSampler(This,desc,descriptor) (This)->lpVtbl->CreateSampler(This,desc,descriptor)
+#define ID3D12Device_CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type) (This)->lpVtbl->CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type)
+#define ID3D12Device_CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type) (This)->lpVtbl->CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type)
+#define ID3D12Device_GetResourceAllocationInfo(This,visible_mask,reource_desc_count,resource_descs) ID3D12Device_GetResourceAllocationInfo_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12Device_GetCustomHeapProperties(This,node_mask,heap_type) ID3D12Device_GetCustomHeapProperties_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12Device_CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device_CreateHeap(This,desc,riid,heap) (This)->lpVtbl->CreateHeap(This,desc,riid,heap)
+#define ID3D12Device_CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device_CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device_CreateSharedHandle(This,object,attributes,access,name,handle) (This)->lpVtbl->CreateSharedHandle(This,object,attributes,access,name,handle)
+#define ID3D12Device_OpenSharedHandle(This,handle,riid,object) (This)->lpVtbl->OpenSharedHandle(This,handle,riid,object)
+#define ID3D12Device_OpenSharedHandleByName(This,name,access,handle) (This)->lpVtbl->OpenSharedHandleByName(This,name,access,handle)
+#define ID3D12Device_MakeResident(This,object_count,objects) (This)->lpVtbl->MakeResident(This,object_count,objects)
+#define ID3D12Device_Evict(This,object_count,objects) (This)->lpVtbl->Evict(This,object_count,objects)
+#define ID3D12Device_CreateFence(This,initial_value,flags,riid,fence) (This)->lpVtbl->CreateFence(This,initial_value,flags,riid,fence)
+#define ID3D12Device_GetDeviceRemovedReason(This) (This)->lpVtbl->GetDeviceRemovedReason(This)
+#define ID3D12Device_GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes) (This)->lpVtbl->GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes)
+#define ID3D12Device_CreateQueryHeap(This,desc,riid,heap) (This)->lpVtbl->CreateQueryHeap(This,desc,riid,heap)
+#define ID3D12Device_SetStablePowerState(This,enable) (This)->lpVtbl->SetStablePowerState(This,enable)
+#define ID3D12Device_CreateCommandSignature(This,desc,root_signature,riid,command_signature) (This)->lpVtbl->CreateCommandSignature(This,desc,root_signature,riid,command_signature)
+#define ID3D12Device_GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings) (This)->lpVtbl->GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings)
+#define ID3D12Device_GetAdapterLuid(This) ID3D12Device_GetAdapterLuid_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Device_QueryInterface(ID3D12Device* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Device_AddRef(ID3D12Device* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Device_Release(ID3D12Device* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Device_GetPrivateData(ID3D12Device* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Device_SetPrivateData(ID3D12Device* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Device_SetPrivateDataInterface(ID3D12Device* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Device_SetName(ID3D12Device* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12Device methods ***/
+static FORCEINLINE UINT ID3D12Device_GetNodeCount(ID3D12Device* This) {
+    return This->lpVtbl->GetNodeCount(This);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateCommandQueue(ID3D12Device* This,const D3D12_COMMAND_QUEUE_DESC *desc,REFIID riid,void **command_queue) {
+    return This->lpVtbl->CreateCommandQueue(This,desc,riid,command_queue);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateCommandAllocator(ID3D12Device* This,D3D12_COMMAND_LIST_TYPE type,REFIID riid,void **command_allocator) {
+    return This->lpVtbl->CreateCommandAllocator(This,type,riid,command_allocator);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateGraphicsPipelineState(ID3D12Device* This,const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,REFIID riid,void **pipeline_state) {
+    return This->lpVtbl->CreateGraphicsPipelineState(This,desc,riid,pipeline_state);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateComputePipelineState(ID3D12Device* This,const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,REFIID riid,void **pipeline_state) {
+    return This->lpVtbl->CreateComputePipelineState(This,desc,riid,pipeline_state);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateCommandList(ID3D12Device* This,UINT node_mask,D3D12_COMMAND_LIST_TYPE type,ID3D12CommandAllocator *command_allocator,ID3D12PipelineState *initial_pipeline_state,REFIID riid,void **command_list) {
+    return This->lpVtbl->CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list);
+}
+static FORCEINLINE HRESULT ID3D12Device_CheckFeatureSupport(ID3D12Device* This,D3D12_FEATURE feature,void *feature_data,UINT feature_data_size) {
+    return This->lpVtbl->CheckFeatureSupport(This,feature,feature_data,feature_data_size);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateDescriptorHeap(ID3D12Device* This,const D3D12_DESCRIPTOR_HEAP_DESC *desc,REFIID riid,void **descriptor_heap) {
+    return This->lpVtbl->CreateDescriptorHeap(This,desc,riid,descriptor_heap);
+}
+static FORCEINLINE UINT ID3D12Device_GetDescriptorHandleIncrementSize(ID3D12Device* This,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    return This->lpVtbl->GetDescriptorHandleIncrementSize(This,descriptor_heap_type);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateRootSignature(ID3D12Device* This,UINT node_mask,const void *bytecode,SIZE_T bytecode_length,REFIID riid,void **root_signature) {
+    return This->lpVtbl->CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature);
+}
+static FORCEINLINE void ID3D12Device_CreateConstantBufferView(ID3D12Device* This,const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateConstantBufferView(This,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CreateShaderResourceView(ID3D12Device* This,ID3D12Resource *resource,const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateShaderResourceView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CreateUnorderedAccessView(ID3D12Device* This,ID3D12Resource *resource,ID3D12Resource *counter_resource,const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CreateRenderTargetView(ID3D12Device* This,ID3D12Resource *resource,const D3D12_RENDER_TARGET_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateRenderTargetView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CreateDepthStencilView(ID3D12Device* This,ID3D12Resource *resource,const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateDepthStencilView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CreateSampler(ID3D12Device* This,const D3D12_SAMPLER_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateSampler(This,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device_CopyDescriptors(ID3D12Device* This,UINT dst_descriptor_range_count,const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,const UINT *dst_descriptor_range_sizes,UINT src_descriptor_range_count,const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,const UINT *src_descriptor_range_sizes,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    This->lpVtbl->CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type);
+}
+static FORCEINLINE void ID3D12Device_CopyDescriptorsSimple(ID3D12Device* This,UINT descriptor_count,const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    This->lpVtbl->CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type);
+}
+static FORCEINLINE D3D12_RESOURCE_ALLOCATION_INFO ID3D12Device_GetResourceAllocationInfo(ID3D12Device* This,UINT visible_mask,UINT reource_desc_count,const D3D12_RESOURCE_DESC *resource_descs) {
+    D3D12_RESOURCE_ALLOCATION_INFO __ret;
+    return *This->lpVtbl->GetResourceAllocationInfo(This,&__ret,visible_mask,reource_desc_count,resource_descs);
+}
+static FORCEINLINE D3D12_HEAP_PROPERTIES ID3D12Device_GetCustomHeapProperties(ID3D12Device* This,UINT node_mask,D3D12_HEAP_TYPE heap_type) {
+    D3D12_HEAP_PROPERTIES __ret;
+    return *This->lpVtbl->GetCustomHeapProperties(This,&__ret,node_mask,heap_type);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateCommittedResource(ID3D12Device* This,const D3D12_HEAP_PROPERTIES *heap_properties,D3D12_HEAP_FLAGS heap_flags,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateHeap(ID3D12Device* This,const D3D12_HEAP_DESC *desc,REFIID riid,void **heap) {
+    return This->lpVtbl->CreateHeap(This,desc,riid,heap);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreatePlacedResource(ID3D12Device* This,ID3D12Heap *heap,UINT64 heap_offset,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateReservedResource(ID3D12Device* This,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateSharedHandle(ID3D12Device* This,ID3D12DeviceChild *object,const SECURITY_ATTRIBUTES *attributes,DWORD access,const WCHAR *name,HANDLE *handle) {
+    return This->lpVtbl->CreateSharedHandle(This,object,attributes,access,name,handle);
+}
+static FORCEINLINE HRESULT ID3D12Device_OpenSharedHandle(ID3D12Device* This,HANDLE handle,REFIID riid,void **object) {
+    return This->lpVtbl->OpenSharedHandle(This,handle,riid,object);
+}
+static FORCEINLINE HRESULT ID3D12Device_OpenSharedHandleByName(ID3D12Device* This,const WCHAR *name,DWORD access,HANDLE *handle) {
+    return This->lpVtbl->OpenSharedHandleByName(This,name,access,handle);
+}
+static FORCEINLINE HRESULT ID3D12Device_MakeResident(ID3D12Device* This,UINT object_count,ID3D12Pageable *const *objects) {
+    return This->lpVtbl->MakeResident(This,object_count,objects);
+}
+static FORCEINLINE HRESULT ID3D12Device_Evict(ID3D12Device* This,UINT object_count,ID3D12Pageable *const *objects) {
+    return This->lpVtbl->Evict(This,object_count,objects);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateFence(ID3D12Device* This,UINT64 initial_value,D3D12_FENCE_FLAGS flags,REFIID riid,void **fence) {
+    return This->lpVtbl->CreateFence(This,initial_value,flags,riid,fence);
+}
+static FORCEINLINE HRESULT ID3D12Device_GetDeviceRemovedReason(ID3D12Device* This) {
+    return This->lpVtbl->GetDeviceRemovedReason(This);
+}
+static FORCEINLINE void ID3D12Device_GetCopyableFootprints(ID3D12Device* This,const D3D12_RESOURCE_DESC *desc,UINT first_sub_resource,UINT sub_resource_count,UINT64 base_offset,D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,UINT *row_count,UINT64 *row_size,UINT64 *total_bytes) {
+    This->lpVtbl->GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateQueryHeap(ID3D12Device* This,const D3D12_QUERY_HEAP_DESC *desc,REFIID riid,void **heap) {
+    return This->lpVtbl->CreateQueryHeap(This,desc,riid,heap);
+}
+static FORCEINLINE HRESULT ID3D12Device_SetStablePowerState(ID3D12Device* This,BOOL enable) {
+    return This->lpVtbl->SetStablePowerState(This,enable);
+}
+static FORCEINLINE HRESULT ID3D12Device_CreateCommandSignature(ID3D12Device* This,const D3D12_COMMAND_SIGNATURE_DESC *desc,ID3D12RootSignature *root_signature,REFIID riid,void **command_signature) {
+    return This->lpVtbl->CreateCommandSignature(This,desc,root_signature,riid,command_signature);
+}
+static FORCEINLINE void ID3D12Device_GetResourceTiling(ID3D12Device* This,ID3D12Resource *resource,UINT *total_tile_count,D3D12_PACKED_MIP_INFO *packed_mip_info,D3D12_TILE_SHAPE *standard_tile_shape,UINT *sub_resource_tiling_count,UINT first_sub_resource_tiling,D3D12_SUBRESOURCE_TILING *sub_resource_tilings) {
+    This->lpVtbl->GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings);
+}
+static FORCEINLINE LUID ID3D12Device_GetAdapterLuid(ID3D12Device* This) {
+    LUID __ret;
+    return *This->lpVtbl->GetAdapterLuid(This,&__ret);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Device_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Device1 interface
+ */
+#ifndef __ID3D12Device1_INTERFACE_DEFINED__
+#define __ID3D12Device1_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Device1, 0x77acce80, 0x638e, 0x4e65, 0x88,0x95, 0xc1,0xf2,0x33,0x86,0x86,0x3e);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("77acce80-638e-4e65-8895-c1f23386863e")
+ID3D12Device1 : public ID3D12Device
+{
+    virtual HRESULT STDMETHODCALLTYPE CreatePipelineLibrary(
+        const void *blob,
+        SIZE_T blob_size,
+        REFIID iid,
+        void **lib) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetEventOnMultipleFenceCompletion(
+        ID3D12Fence *const *fences,
+        const UINT64 *values,
+        UINT fence_count,
+        D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags,
+        HANDLE event) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetResidencyPriority(
+        UINT object_count,
+        ID3D12Pageable *const *objects,
+        const D3D12_RESIDENCY_PRIORITY *priorities) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Device1, 0x77acce80, 0x638e, 0x4e65, 0x88,0x95, 0xc1,0xf2,0x33,0x86,0x86,0x3e)
+#endif
+#else
+typedef struct ID3D12Device1Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Device1 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Device1 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Device1 *This);
+
+    /*** ID3D12Object methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        ID3D12Device1 *This,
+        REFGUID guid,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        ID3D12Device1 *This,
+        REFGUID guid,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetPrivateDataInterface)(
+        ID3D12Device1 *This,
+        REFGUID guid,
+        const IUnknown *data);
+
+    HRESULT (STDMETHODCALLTYPE *SetName)(
+        ID3D12Device1 *This,
+        const WCHAR *name);
+
+    /*** ID3D12Device methods ***/
+    UINT (STDMETHODCALLTYPE *GetNodeCount)(
+        ID3D12Device1 *This);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandQueue)(
+        ID3D12Device1 *This,
+        const D3D12_COMMAND_QUEUE_DESC *desc,
+        REFIID riid,
+        void **command_queue);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandAllocator)(
+        ID3D12Device1 *This,
+        D3D12_COMMAND_LIST_TYPE type,
+        REFIID riid,
+        void **command_allocator);
+
+    HRESULT (STDMETHODCALLTYPE *CreateGraphicsPipelineState)(
+        ID3D12Device1 *This,
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state);
+
+    HRESULT (STDMETHODCALLTYPE *CreateComputePipelineState)(
+        ID3D12Device1 *This,
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,
+        REFIID riid,
+        void **pipeline_state);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandList)(
+        ID3D12Device1 *This,
+        UINT node_mask,
+        D3D12_COMMAND_LIST_TYPE type,
+        ID3D12CommandAllocator *command_allocator,
+        ID3D12PipelineState *initial_pipeline_state,
+        REFIID riid,
+        void **command_list);
+
+    HRESULT (STDMETHODCALLTYPE *CheckFeatureSupport)(
+        ID3D12Device1 *This,
+        D3D12_FEATURE feature,
+        void *feature_data,
+        UINT feature_data_size);
+
+    HRESULT (STDMETHODCALLTYPE *CreateDescriptorHeap)(
+        ID3D12Device1 *This,
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc,
+        REFIID riid,
+        void **descriptor_heap);
+
+    UINT (STDMETHODCALLTYPE *GetDescriptorHandleIncrementSize)(
+        ID3D12Device1 *This,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    HRESULT (STDMETHODCALLTYPE *CreateRootSignature)(
+        ID3D12Device1 *This,
+        UINT node_mask,
+        const void *bytecode,
+        SIZE_T bytecode_length,
+        REFIID riid,
+        void **root_signature);
+
+    void (STDMETHODCALLTYPE *CreateConstantBufferView)(
+        ID3D12Device1 *This,
+        const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateShaderResourceView)(
+        ID3D12Device1 *This,
+        ID3D12Resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateUnorderedAccessView)(
+        ID3D12Device1 *This,
+        ID3D12Resource *resource,
+        ID3D12Resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateRenderTargetView)(
+        ID3D12Device1 *This,
+        ID3D12Resource *resource,
+        const D3D12_RENDER_TARGET_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateDepthStencilView)(
+        ID3D12Device1 *This,
+        ID3D12Resource *resource,
+        const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CreateSampler)(
+        ID3D12Device1 *This,
+        const D3D12_SAMPLER_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void (STDMETHODCALLTYPE *CopyDescriptors)(
+        ID3D12Device1 *This,
+        UINT dst_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
+        const UINT *dst_descriptor_range_sizes,
+        UINT src_descriptor_range_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
+        const UINT *src_descriptor_range_sizes,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    void (STDMETHODCALLTYPE *CopyDescriptorsSimple)(
+        ID3D12Device1 *This,
+        UINT descriptor_count,
+        const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
+        const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    D3D12_RESOURCE_ALLOCATION_INFO * (STDMETHODCALLTYPE *GetResourceAllocationInfo)(
+        ID3D12Device1 *This,
+        D3D12_RESOURCE_ALLOCATION_INFO *__ret,
+        UINT visible_mask,
+        UINT reource_desc_count,
+        const D3D12_RESOURCE_DESC *resource_descs);
+
+    D3D12_HEAP_PROPERTIES * (STDMETHODCALLTYPE *GetCustomHeapProperties)(
+        ID3D12Device1 *This,
+        D3D12_HEAP_PROPERTIES *__ret,
+        UINT node_mask,
+        D3D12_HEAP_TYPE heap_type);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommittedResource)(
+        ID3D12Device1 *This,
+        const D3D12_HEAP_PROPERTIES *heap_properties,
+        D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateHeap)(
+        ID3D12Device1 *This,
+        const D3D12_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap);
+
+    HRESULT (STDMETHODCALLTYPE *CreatePlacedResource)(
+        ID3D12Device1 *This,
+        ID3D12Heap *heap,
+        UINT64 heap_offset,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateReservedResource)(
+        ID3D12Device1 *This,
+        const D3D12_RESOURCE_DESC *desc,
+        D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value,
+        REFIID riid,
+        void **resource);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSharedHandle)(
+        ID3D12Device1 *This,
+        ID3D12DeviceChild *object,
+        const SECURITY_ATTRIBUTES *attributes,
+        DWORD access,
+        const WCHAR *name,
+        HANDLE *handle);
+
+    HRESULT (STDMETHODCALLTYPE *OpenSharedHandle)(
+        ID3D12Device1 *This,
+        HANDLE handle,
+        REFIID riid,
+        void **object);
+
+    HRESULT (STDMETHODCALLTYPE *OpenSharedHandleByName)(
+        ID3D12Device1 *This,
+        const WCHAR *name,
+        DWORD access,
+        HANDLE *handle);
+
+    HRESULT (STDMETHODCALLTYPE *MakeResident)(
+        ID3D12Device1 *This,
+        UINT object_count,
+        ID3D12Pageable *const *objects);
+
+    HRESULT (STDMETHODCALLTYPE *Evict)(
+        ID3D12Device1 *This,
+        UINT object_count,
+        ID3D12Pageable *const *objects);
+
+    HRESULT (STDMETHODCALLTYPE *CreateFence)(
+        ID3D12Device1 *This,
+        UINT64 initial_value,
+        D3D12_FENCE_FLAGS flags,
+        REFIID riid,
+        void **fence);
+
+    HRESULT (STDMETHODCALLTYPE *GetDeviceRemovedReason)(
+        ID3D12Device1 *This);
+
+    void (STDMETHODCALLTYPE *GetCopyableFootprints)(
+        ID3D12Device1 *This,
+        const D3D12_RESOURCE_DESC *desc,
+        UINT first_sub_resource,
+        UINT sub_resource_count,
+        UINT64 base_offset,
+        D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
+        UINT *row_count,
+        UINT64 *row_size,
+        UINT64 *total_bytes);
+
+    HRESULT (STDMETHODCALLTYPE *CreateQueryHeap)(
+        ID3D12Device1 *This,
+        const D3D12_QUERY_HEAP_DESC *desc,
+        REFIID riid,
+        void **heap);
+
+    HRESULT (STDMETHODCALLTYPE *SetStablePowerState)(
+        ID3D12Device1 *This,
+        BOOL enable);
+
+    HRESULT (STDMETHODCALLTYPE *CreateCommandSignature)(
+        ID3D12Device1 *This,
+        const D3D12_COMMAND_SIGNATURE_DESC *desc,
+        ID3D12RootSignature *root_signature,
+        REFIID riid,
+        void **command_signature);
+
+    void (STDMETHODCALLTYPE *GetResourceTiling)(
+        ID3D12Device1 *This,
+        ID3D12Resource *resource,
+        UINT *total_tile_count,
+        D3D12_PACKED_MIP_INFO *packed_mip_info,
+        D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *sub_resource_tiling_count,
+        UINT first_sub_resource_tiling,
+        D3D12_SUBRESOURCE_TILING *sub_resource_tilings);
+
+    LUID * (STDMETHODCALLTYPE *GetAdapterLuid)(
+        ID3D12Device1 *This,
+        LUID *__ret);
+
+    /*** ID3D12Device1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *CreatePipelineLibrary)(
+        ID3D12Device1 *This,
+        const void *blob,
+        SIZE_T blob_size,
+        REFIID iid,
+        void **lib);
+
+    HRESULT (STDMETHODCALLTYPE *SetEventOnMultipleFenceCompletion)(
+        ID3D12Device1 *This,
+        ID3D12Fence *const *fences,
+        const UINT64 *values,
+        UINT fence_count,
+        D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags,
+        HANDLE event);
+
+    HRESULT (STDMETHODCALLTYPE *SetResidencyPriority)(
+        ID3D12Device1 *This,
+        UINT object_count,
+        ID3D12Pageable *const *objects,
+        const D3D12_RESIDENCY_PRIORITY *priorities);
+
+    END_INTERFACE
+} ID3D12Device1Vtbl;
+
+interface ID3D12Device1 {
+    CONST_VTBL ID3D12Device1Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Device1_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Device1_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Device1_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Object methods ***/
+#define ID3D12Device1_GetPrivateData(This,guid,data_size,data) (This)->lpVtbl->GetPrivateData(This,guid,data_size,data)
+#define ID3D12Device1_SetPrivateData(This,guid,data_size,data) (This)->lpVtbl->SetPrivateData(This,guid,data_size,data)
+#define ID3D12Device1_SetPrivateDataInterface(This,guid,data) (This)->lpVtbl->SetPrivateDataInterface(This,guid,data)
+#define ID3D12Device1_SetName(This,name) (This)->lpVtbl->SetName(This,name)
+/*** ID3D12Device methods ***/
+#define ID3D12Device1_GetNodeCount(This) (This)->lpVtbl->GetNodeCount(This)
+#define ID3D12Device1_CreateCommandQueue(This,desc,riid,command_queue) (This)->lpVtbl->CreateCommandQueue(This,desc,riid,command_queue)
+#define ID3D12Device1_CreateCommandAllocator(This,type,riid,command_allocator) (This)->lpVtbl->CreateCommandAllocator(This,type,riid,command_allocator)
+#define ID3D12Device1_CreateGraphicsPipelineState(This,desc,riid,pipeline_state) (This)->lpVtbl->CreateGraphicsPipelineState(This,desc,riid,pipeline_state)
+#define ID3D12Device1_CreateComputePipelineState(This,desc,riid,pipeline_state) (This)->lpVtbl->CreateComputePipelineState(This,desc,riid,pipeline_state)
+#define ID3D12Device1_CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list) (This)->lpVtbl->CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list)
+#define ID3D12Device1_CheckFeatureSupport(This,feature,feature_data,feature_data_size) (This)->lpVtbl->CheckFeatureSupport(This,feature,feature_data,feature_data_size)
+#define ID3D12Device1_CreateDescriptorHeap(This,desc,riid,descriptor_heap) (This)->lpVtbl->CreateDescriptorHeap(This,desc,riid,descriptor_heap)
+#define ID3D12Device1_GetDescriptorHandleIncrementSize(This,descriptor_heap_type) (This)->lpVtbl->GetDescriptorHandleIncrementSize(This,descriptor_heap_type)
+#define ID3D12Device1_CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature) (This)->lpVtbl->CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature)
+#define ID3D12Device1_CreateConstantBufferView(This,desc,descriptor) (This)->lpVtbl->CreateConstantBufferView(This,desc,descriptor)
+#define ID3D12Device1_CreateShaderResourceView(This,resource,desc,descriptor) (This)->lpVtbl->CreateShaderResourceView(This,resource,desc,descriptor)
+#define ID3D12Device1_CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor) (This)->lpVtbl->CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor)
+#define ID3D12Device1_CreateRenderTargetView(This,resource,desc,descriptor) (This)->lpVtbl->CreateRenderTargetView(This,resource,desc,descriptor)
+#define ID3D12Device1_CreateDepthStencilView(This,resource,desc,descriptor) (This)->lpVtbl->CreateDepthStencilView(This,resource,desc,descriptor)
+#define ID3D12Device1_CreateSampler(This,desc,descriptor) (This)->lpVtbl->CreateSampler(This,desc,descriptor)
+#define ID3D12Device1_CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type) (This)->lpVtbl->CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type)
+#define ID3D12Device1_CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type) (This)->lpVtbl->CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type)
+#define ID3D12Device1_GetResourceAllocationInfo(This,visible_mask,reource_desc_count,resource_descs) ID3D12Device1_GetResourceAllocationInfo_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12Device1_GetCustomHeapProperties(This,node_mask,heap_type) ID3D12Device1_GetCustomHeapProperties_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+#define ID3D12Device1_CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device1_CreateHeap(This,desc,riid,heap) (This)->lpVtbl->CreateHeap(This,desc,riid,heap)
+#define ID3D12Device1_CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device1_CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource) (This)->lpVtbl->CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource)
+#define ID3D12Device1_CreateSharedHandle(This,object,attributes,access,name,handle) (This)->lpVtbl->CreateSharedHandle(This,object,attributes,access,name,handle)
+#define ID3D12Device1_OpenSharedHandle(This,handle,riid,object) (This)->lpVtbl->OpenSharedHandle(This,handle,riid,object)
+#define ID3D12Device1_OpenSharedHandleByName(This,name,access,handle) (This)->lpVtbl->OpenSharedHandleByName(This,name,access,handle)
+#define ID3D12Device1_MakeResident(This,object_count,objects) (This)->lpVtbl->MakeResident(This,object_count,objects)
+#define ID3D12Device1_Evict(This,object_count,objects) (This)->lpVtbl->Evict(This,object_count,objects)
+#define ID3D12Device1_CreateFence(This,initial_value,flags,riid,fence) (This)->lpVtbl->CreateFence(This,initial_value,flags,riid,fence)
+#define ID3D12Device1_GetDeviceRemovedReason(This) (This)->lpVtbl->GetDeviceRemovedReason(This)
+#define ID3D12Device1_GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes) (This)->lpVtbl->GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes)
+#define ID3D12Device1_CreateQueryHeap(This,desc,riid,heap) (This)->lpVtbl->CreateQueryHeap(This,desc,riid,heap)
+#define ID3D12Device1_SetStablePowerState(This,enable) (This)->lpVtbl->SetStablePowerState(This,enable)
+#define ID3D12Device1_CreateCommandSignature(This,desc,root_signature,riid,command_signature) (This)->lpVtbl->CreateCommandSignature(This,desc,root_signature,riid,command_signature)
+#define ID3D12Device1_GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings) (This)->lpVtbl->GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings)
+#define ID3D12Device1_GetAdapterLuid(This) ID3D12Device1_GetAdapterLuid_define_WIDL_C_INLINE_WRAPPERS_for_aggregate_return_support
+/*** ID3D12Device1 methods ***/
+#define ID3D12Device1_CreatePipelineLibrary(This,blob,blob_size,iid,lib) (This)->lpVtbl->CreatePipelineLibrary(This,blob,blob_size,iid,lib)
+#define ID3D12Device1_SetEventOnMultipleFenceCompletion(This,fences,values,fence_count,flags,event) (This)->lpVtbl->SetEventOnMultipleFenceCompletion(This,fences,values,fence_count,flags,event)
+#define ID3D12Device1_SetResidencyPriority(This,object_count,objects,priorities) (This)->lpVtbl->SetResidencyPriority(This,object_count,objects,priorities)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Device1_QueryInterface(ID3D12Device1* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Device1_AddRef(ID3D12Device1* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Device1_Release(ID3D12Device1* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Object methods ***/
+static FORCEINLINE HRESULT ID3D12Device1_GetPrivateData(ID3D12Device1* This,REFGUID guid,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetPrivateData(ID3D12Device1* This,REFGUID guid,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,guid,data_size,data);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetPrivateDataInterface(ID3D12Device1* This,REFGUID guid,const IUnknown *data) {
+    return This->lpVtbl->SetPrivateDataInterface(This,guid,data);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetName(ID3D12Device1* This,const WCHAR *name) {
+    return This->lpVtbl->SetName(This,name);
+}
+/*** ID3D12Device methods ***/
+static FORCEINLINE UINT ID3D12Device1_GetNodeCount(ID3D12Device1* This) {
+    return This->lpVtbl->GetNodeCount(This);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateCommandQueue(ID3D12Device1* This,const D3D12_COMMAND_QUEUE_DESC *desc,REFIID riid,void **command_queue) {
+    return This->lpVtbl->CreateCommandQueue(This,desc,riid,command_queue);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateCommandAllocator(ID3D12Device1* This,D3D12_COMMAND_LIST_TYPE type,REFIID riid,void **command_allocator) {
+    return This->lpVtbl->CreateCommandAllocator(This,type,riid,command_allocator);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateGraphicsPipelineState(ID3D12Device1* This,const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,REFIID riid,void **pipeline_state) {
+    return This->lpVtbl->CreateGraphicsPipelineState(This,desc,riid,pipeline_state);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateComputePipelineState(ID3D12Device1* This,const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,REFIID riid,void **pipeline_state) {
+    return This->lpVtbl->CreateComputePipelineState(This,desc,riid,pipeline_state);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateCommandList(ID3D12Device1* This,UINT node_mask,D3D12_COMMAND_LIST_TYPE type,ID3D12CommandAllocator *command_allocator,ID3D12PipelineState *initial_pipeline_state,REFIID riid,void **command_list) {
+    return This->lpVtbl->CreateCommandList(This,node_mask,type,command_allocator,initial_pipeline_state,riid,command_list);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CheckFeatureSupport(ID3D12Device1* This,D3D12_FEATURE feature,void *feature_data,UINT feature_data_size) {
+    return This->lpVtbl->CheckFeatureSupport(This,feature,feature_data,feature_data_size);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateDescriptorHeap(ID3D12Device1* This,const D3D12_DESCRIPTOR_HEAP_DESC *desc,REFIID riid,void **descriptor_heap) {
+    return This->lpVtbl->CreateDescriptorHeap(This,desc,riid,descriptor_heap);
+}
+static FORCEINLINE UINT ID3D12Device1_GetDescriptorHandleIncrementSize(ID3D12Device1* This,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    return This->lpVtbl->GetDescriptorHandleIncrementSize(This,descriptor_heap_type);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateRootSignature(ID3D12Device1* This,UINT node_mask,const void *bytecode,SIZE_T bytecode_length,REFIID riid,void **root_signature) {
+    return This->lpVtbl->CreateRootSignature(This,node_mask,bytecode,bytecode_length,riid,root_signature);
+}
+static FORCEINLINE void ID3D12Device1_CreateConstantBufferView(ID3D12Device1* This,const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateConstantBufferView(This,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CreateShaderResourceView(ID3D12Device1* This,ID3D12Resource *resource,const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateShaderResourceView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CreateUnorderedAccessView(ID3D12Device1* This,ID3D12Resource *resource,ID3D12Resource *counter_resource,const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateUnorderedAccessView(This,resource,counter_resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CreateRenderTargetView(ID3D12Device1* This,ID3D12Resource *resource,const D3D12_RENDER_TARGET_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateRenderTargetView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CreateDepthStencilView(ID3D12Device1* This,ID3D12Resource *resource,const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateDepthStencilView(This,resource,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CreateSampler(ID3D12Device1* This,const D3D12_SAMPLER_DESC *desc,D3D12_CPU_DESCRIPTOR_HANDLE descriptor) {
+    This->lpVtbl->CreateSampler(This,desc,descriptor);
+}
+static FORCEINLINE void ID3D12Device1_CopyDescriptors(ID3D12Device1* This,UINT dst_descriptor_range_count,const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,const UINT *dst_descriptor_range_sizes,UINT src_descriptor_range_count,const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,const UINT *src_descriptor_range_sizes,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    This->lpVtbl->CopyDescriptors(This,dst_descriptor_range_count,dst_descriptor_range_offsets,dst_descriptor_range_sizes,src_descriptor_range_count,src_descriptor_range_offsets,src_descriptor_range_sizes,descriptor_heap_type);
+}
+static FORCEINLINE void ID3D12Device1_CopyDescriptorsSimple(ID3D12Device1* This,UINT descriptor_count,const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type) {
+    This->lpVtbl->CopyDescriptorsSimple(This,descriptor_count,dst_descriptor_range_offset,src_descriptor_range_offset,descriptor_heap_type);
+}
+static FORCEINLINE D3D12_RESOURCE_ALLOCATION_INFO ID3D12Device1_GetResourceAllocationInfo(ID3D12Device1* This,UINT visible_mask,UINT reource_desc_count,const D3D12_RESOURCE_DESC *resource_descs) {
+    D3D12_RESOURCE_ALLOCATION_INFO __ret;
+    return *This->lpVtbl->GetResourceAllocationInfo(This,&__ret,visible_mask,reource_desc_count,resource_descs);
+}
+static FORCEINLINE D3D12_HEAP_PROPERTIES ID3D12Device1_GetCustomHeapProperties(ID3D12Device1* This,UINT node_mask,D3D12_HEAP_TYPE heap_type) {
+    D3D12_HEAP_PROPERTIES __ret;
+    return *This->lpVtbl->GetCustomHeapProperties(This,&__ret,node_mask,heap_type);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateCommittedResource(ID3D12Device1* This,const D3D12_HEAP_PROPERTIES *heap_properties,D3D12_HEAP_FLAGS heap_flags,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreateCommittedResource(This,heap_properties,heap_flags,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateHeap(ID3D12Device1* This,const D3D12_HEAP_DESC *desc,REFIID riid,void **heap) {
+    return This->lpVtbl->CreateHeap(This,desc,riid,heap);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreatePlacedResource(ID3D12Device1* This,ID3D12Heap *heap,UINT64 heap_offset,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreatePlacedResource(This,heap,heap_offset,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateReservedResource(ID3D12Device1* This,const D3D12_RESOURCE_DESC *desc,D3D12_RESOURCE_STATES initial_state,const D3D12_CLEAR_VALUE *optimized_clear_value,REFIID riid,void **resource) {
+    return This->lpVtbl->CreateReservedResource(This,desc,initial_state,optimized_clear_value,riid,resource);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateSharedHandle(ID3D12Device1* This,ID3D12DeviceChild *object,const SECURITY_ATTRIBUTES *attributes,DWORD access,const WCHAR *name,HANDLE *handle) {
+    return This->lpVtbl->CreateSharedHandle(This,object,attributes,access,name,handle);
+}
+static FORCEINLINE HRESULT ID3D12Device1_OpenSharedHandle(ID3D12Device1* This,HANDLE handle,REFIID riid,void **object) {
+    return This->lpVtbl->OpenSharedHandle(This,handle,riid,object);
+}
+static FORCEINLINE HRESULT ID3D12Device1_OpenSharedHandleByName(ID3D12Device1* This,const WCHAR *name,DWORD access,HANDLE *handle) {
+    return This->lpVtbl->OpenSharedHandleByName(This,name,access,handle);
+}
+static FORCEINLINE HRESULT ID3D12Device1_MakeResident(ID3D12Device1* This,UINT object_count,ID3D12Pageable *const *objects) {
+    return This->lpVtbl->MakeResident(This,object_count,objects);
+}
+static FORCEINLINE HRESULT ID3D12Device1_Evict(ID3D12Device1* This,UINT object_count,ID3D12Pageable *const *objects) {
+    return This->lpVtbl->Evict(This,object_count,objects);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateFence(ID3D12Device1* This,UINT64 initial_value,D3D12_FENCE_FLAGS flags,REFIID riid,void **fence) {
+    return This->lpVtbl->CreateFence(This,initial_value,flags,riid,fence);
+}
+static FORCEINLINE HRESULT ID3D12Device1_GetDeviceRemovedReason(ID3D12Device1* This) {
+    return This->lpVtbl->GetDeviceRemovedReason(This);
+}
+static FORCEINLINE void ID3D12Device1_GetCopyableFootprints(ID3D12Device1* This,const D3D12_RESOURCE_DESC *desc,UINT first_sub_resource,UINT sub_resource_count,UINT64 base_offset,D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,UINT *row_count,UINT64 *row_size,UINT64 *total_bytes) {
+    This->lpVtbl->GetCopyableFootprints(This,desc,first_sub_resource,sub_resource_count,base_offset,layouts,row_count,row_size,total_bytes);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateQueryHeap(ID3D12Device1* This,const D3D12_QUERY_HEAP_DESC *desc,REFIID riid,void **heap) {
+    return This->lpVtbl->CreateQueryHeap(This,desc,riid,heap);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetStablePowerState(ID3D12Device1* This,BOOL enable) {
+    return This->lpVtbl->SetStablePowerState(This,enable);
+}
+static FORCEINLINE HRESULT ID3D12Device1_CreateCommandSignature(ID3D12Device1* This,const D3D12_COMMAND_SIGNATURE_DESC *desc,ID3D12RootSignature *root_signature,REFIID riid,void **command_signature) {
+    return This->lpVtbl->CreateCommandSignature(This,desc,root_signature,riid,command_signature);
+}
+static FORCEINLINE void ID3D12Device1_GetResourceTiling(ID3D12Device1* This,ID3D12Resource *resource,UINT *total_tile_count,D3D12_PACKED_MIP_INFO *packed_mip_info,D3D12_TILE_SHAPE *standard_tile_shape,UINT *sub_resource_tiling_count,UINT first_sub_resource_tiling,D3D12_SUBRESOURCE_TILING *sub_resource_tilings) {
+    This->lpVtbl->GetResourceTiling(This,resource,total_tile_count,packed_mip_info,standard_tile_shape,sub_resource_tiling_count,first_sub_resource_tiling,sub_resource_tilings);
+}
+static FORCEINLINE LUID ID3D12Device1_GetAdapterLuid(ID3D12Device1* This) {
+    LUID __ret;
+    return *This->lpVtbl->GetAdapterLuid(This,&__ret);
+}
+/*** ID3D12Device1 methods ***/
+static FORCEINLINE HRESULT ID3D12Device1_CreatePipelineLibrary(ID3D12Device1* This,const void *blob,SIZE_T blob_size,REFIID iid,void **lib) {
+    return This->lpVtbl->CreatePipelineLibrary(This,blob,blob_size,iid,lib);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetEventOnMultipleFenceCompletion(ID3D12Device1* This,ID3D12Fence *const *fences,const UINT64 *values,UINT fence_count,D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags,HANDLE event) {
+    return This->lpVtbl->SetEventOnMultipleFenceCompletion(This,fences,values,fence_count,flags,event);
+}
+static FORCEINLINE HRESULT ID3D12Device1_SetResidencyPriority(ID3D12Device1* This,UINT object_count,ID3D12Pageable *const *objects,const D3D12_RESIDENCY_PRIORITY *priorities) {
+    return This->lpVtbl->SetResidencyPriority(This,object_count,objects,priorities);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Device1_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12RootSignatureDeserializer interface
+ */
+#ifndef __ID3D12RootSignatureDeserializer_INTERFACE_DEFINED__
+#define __ID3D12RootSignatureDeserializer_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12RootSignatureDeserializer, 0x34ab647b, 0x3cc8, 0x46ac, 0x84,0x1b, 0xc0,0x96,0x56,0x45,0xc0,0x46);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("34ab647b-3cc8-46ac-841b-c0965645c046")
+ID3D12RootSignatureDeserializer : public IUnknown
+{
+    virtual const D3D12_ROOT_SIGNATURE_DESC * STDMETHODCALLTYPE GetRootSignatureDesc(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12RootSignatureDeserializer, 0x34ab647b, 0x3cc8, 0x46ac, 0x84,0x1b, 0xc0,0x96,0x56,0x45,0xc0,0x46)
+#endif
+#else
+typedef struct ID3D12RootSignatureDeserializerVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12RootSignatureDeserializer *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12RootSignatureDeserializer *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12RootSignatureDeserializer *This);
+
+    /*** ID3D12RootSignatureDeserializer methods ***/
+    const D3D12_ROOT_SIGNATURE_DESC * (STDMETHODCALLTYPE *GetRootSignatureDesc)(
+        ID3D12RootSignatureDeserializer *This);
+
+    END_INTERFACE
+} ID3D12RootSignatureDeserializerVtbl;
+
+interface ID3D12RootSignatureDeserializer {
+    CONST_VTBL ID3D12RootSignatureDeserializerVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12RootSignatureDeserializer_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12RootSignatureDeserializer_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12RootSignatureDeserializer_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12RootSignatureDeserializer methods ***/
+#define ID3D12RootSignatureDeserializer_GetRootSignatureDesc(This) (This)->lpVtbl->GetRootSignatureDesc(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12RootSignatureDeserializer_QueryInterface(ID3D12RootSignatureDeserializer* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12RootSignatureDeserializer_AddRef(ID3D12RootSignatureDeserializer* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12RootSignatureDeserializer_Release(ID3D12RootSignatureDeserializer* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12RootSignatureDeserializer methods ***/
+static FORCEINLINE const D3D12_ROOT_SIGNATURE_DESC * ID3D12RootSignatureDeserializer_GetRootSignatureDesc(ID3D12RootSignatureDeserializer* This) {
+    return This->lpVtbl->GetRootSignatureDesc(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12RootSignatureDeserializer_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12VersionedRootSignatureDeserializer interface
+ */
+#ifndef __ID3D12VersionedRootSignatureDeserializer_INTERFACE_DEFINED__
+#define __ID3D12VersionedRootSignatureDeserializer_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12VersionedRootSignatureDeserializer, 0x7f91ce67, 0x090c, 0x4bb7, 0xb7,0x8e, 0xed,0x8f,0xf2,0xe3,0x1d,0xa0);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("7f91ce67-090c-4bb7-b78e-ed8ff2e31da0")
+ID3D12VersionedRootSignatureDeserializer : public IUnknown
+{
+    virtual HRESULT STDMETHODCALLTYPE GetRootSignatureDescAtVersion(
+        D3D_ROOT_SIGNATURE_VERSION version,
+        const D3D12_VERSIONED_ROOT_SIGNATURE_DESC **desc) = 0;
+
+    virtual const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * STDMETHODCALLTYPE GetUnconvertedRootSignatureDesc(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12VersionedRootSignatureDeserializer, 0x7f91ce67, 0x090c, 0x4bb7, 0xb7,0x8e, 0xed,0x8f,0xf2,0xe3,0x1d,0xa0)
+#endif
+#else
+typedef struct ID3D12VersionedRootSignatureDeserializerVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12VersionedRootSignatureDeserializer *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12VersionedRootSignatureDeserializer *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12VersionedRootSignatureDeserializer *This);
+
+    /*** ID3D12VersionedRootSignatureDeserializer methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetRootSignatureDescAtVersion)(
+        ID3D12VersionedRootSignatureDeserializer *This,
+        D3D_ROOT_SIGNATURE_VERSION version,
+        const D3D12_VERSIONED_ROOT_SIGNATURE_DESC **desc);
+
+    const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * (STDMETHODCALLTYPE *GetUnconvertedRootSignatureDesc)(
+        ID3D12VersionedRootSignatureDeserializer *This);
+
+    END_INTERFACE
+} ID3D12VersionedRootSignatureDeserializerVtbl;
+
+interface ID3D12VersionedRootSignatureDeserializer {
+    CONST_VTBL ID3D12VersionedRootSignatureDeserializerVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12VersionedRootSignatureDeserializer_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12VersionedRootSignatureDeserializer_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12VersionedRootSignatureDeserializer_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12VersionedRootSignatureDeserializer methods ***/
+#define ID3D12VersionedRootSignatureDeserializer_GetRootSignatureDescAtVersion(This,version,desc) (This)->lpVtbl->GetRootSignatureDescAtVersion(This,version,desc)
+#define ID3D12VersionedRootSignatureDeserializer_GetUnconvertedRootSignatureDesc(This) (This)->lpVtbl->GetUnconvertedRootSignatureDesc(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12VersionedRootSignatureDeserializer_QueryInterface(ID3D12VersionedRootSignatureDeserializer* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12VersionedRootSignatureDeserializer_AddRef(ID3D12VersionedRootSignatureDeserializer* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12VersionedRootSignatureDeserializer_Release(ID3D12VersionedRootSignatureDeserializer* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12VersionedRootSignatureDeserializer methods ***/
+static FORCEINLINE HRESULT ID3D12VersionedRootSignatureDeserializer_GetRootSignatureDescAtVersion(ID3D12VersionedRootSignatureDeserializer* This,D3D_ROOT_SIGNATURE_VERSION version,const D3D12_VERSIONED_ROOT_SIGNATURE_DESC **desc) {
+    return This->lpVtbl->GetRootSignatureDescAtVersion(This,version,desc);
+}
+static FORCEINLINE const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * ID3D12VersionedRootSignatureDeserializer_GetUnconvertedRootSignatureDesc(ID3D12VersionedRootSignatureDeserializer* This) {
+    return This->lpVtbl->GetUnconvertedRootSignatureDesc(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12VersionedRootSignatureDeserializer_INTERFACE_DEFINED__ */
+
+HRESULT __stdcall  D3D12CreateRootSignatureDeserializer(const void *data,SIZE_T data_size,REFIID iid,void **deserializer);
+
+typedef HRESULT (__stdcall *PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER)(const void *data,SIZE_T data_size,REFIID iid,void **deserializer);
+HRESULT __stdcall  D3D12CreateVersionedRootSignatureDeserializer(const void *data,SIZE_T data_size,REFIID iid,void **deserializer);
+
+HRESULT __stdcall  D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *root_signature_desc,D3D_ROOT_SIGNATURE_VERSION version,ID3DBlob **blob,ID3DBlob **error_blob);
+
+typedef HRESULT (__stdcall *PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,ID3DBlob **blob,ID3DBlob **error_blob);
+HRESULT __stdcall  D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *root_signature_desc,ID3DBlob **blob,ID3DBlob **error_blob);
+
+typedef HRESULT (__stdcall *PFN_D3D12_CREATE_DEVICE)(IUnknown *adapter,D3D_FEATURE_LEVEL minimum_feature_level,REFIID iid,void **device);
+HRESULT __stdcall  D3D12CreateDevice(IUnknown *adapter,D3D_FEATURE_LEVEL minimum_feature_level,REFIID iid,void **device);
+
+typedef HRESULT (__stdcall *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID iid,void **debug);
+HRESULT __stdcall  D3D12GetDebugInterface(REFIID iid,void **debug);
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_d3d12_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_d3d12.idl b/dlls/vkd3d/include/vkd3d_d3d12.idl
new file mode 100644
index 00000000000..48b87f09b12
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3d12.idl
@@ -0,0 +1,2547 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_windows.h";
+
+import "vkd3d_dxgibase.idl";
+
+import "vkd3d_d3dcommon.idl";
+
+cpp_quote("#ifndef _D3D12_CONSTANTS")
+cpp_quote("#define _D3D12_CONSTANTS")
+
+const UINT D3D12_CS_TGSM_REGISTER_COUNT = 8192;
+const UINT D3D12_MAX_ROOT_COST = 64;
+const UINT D3D12_VIEWPORT_BOUNDS_MAX = 32767;
+const UINT D3D12_VIEWPORT_BOUNDS_MIN = -32768;
+
+const UINT D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT = 15;
+
+const UINT D3D12_APPEND_ALIGNED_ELEMENT = 0xffffffff;
+cpp_quote("#define D3D12_DEFAULT_BLEND_FACTOR_ALPHA (1.0f)")
+cpp_quote("#define D3D12_DEFAULT_BLEND_FACTOR_BLUE (1.0f)")
+cpp_quote("#define D3D12_DEFAULT_BLEND_FACTOR_GREEN (1.0f)")
+cpp_quote("#define D3D12_DEFAULT_BLEND_FACTOR_RED (1.0f)")
+const UINT D3D12_DEFAULT_DEPTH_BIAS = 0;
+cpp_quote("#define D3D12_DEFAULT_DEPTH_BIAS_CLAMP (0.0f)")
+cpp_quote("#define D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS (0.0f)")
+const UINT D3D12_DEFAULT_STENCIL_READ_MASK = 0xff;
+const UINT D3D12_DEFAULT_STENCIL_WRITE_MASK = 0xff;
+const UINT D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND = 0xffffffff;
+cpp_quote("#define D3D12_FLOAT32_MAX (3.402823466e+38f)")
+const UINT D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32;
+const UINT D3D12_UAV_SLOT_COUNT = 64;
+const UINT D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT = 4096;
+const UINT D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT = 4096;
+const UINT D3D12_REQ_MIP_LEVELS = 15;
+const UINT D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION = 2048;
+const UINT D3D12_REQ_TEXTURE1D_U_DIMENSION = 16384;
+const UINT D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION = 2048;
+const UINT D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION = 16384;
+const UINT D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION = 2048;
+const UINT D3D12_REQ_TEXTURECUBE_DIMENSION = 16384;
+const UINT D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES = 0xffffffff;
+const UINT D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT = 8;
+const UINT D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES = 2048;
+const UINT D3D12_SO_BUFFER_SLOT_COUNT = 4;
+const UINT D3D12_SO_DDI_REGISTER_INDEX_DENOTING_GAP = 0xffffffff;
+const UINT D3D12_SO_NO_RASTERIZED_STREAM = 0xffffffff;
+const UINT D3D12_SO_OUTPUT_COMPONENT_COUNT = 128;
+const UINT D3D12_SO_STREAM_COUNT = 4;
+const UINT D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT = 256;
+const UINT D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT = 4194304;
+const UINT D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT = 65536;
+const UINT D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT = 16;
+const UINT D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT = 65536;
+const UINT D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT = 4096;
+const UINT D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE = 4;
+const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256;
+const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512;
+const UINT D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT = 4096;
+const UINT D3D12_VS_INPUT_REGISTER_COUNT = 32;
+const UINT D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE = 16;
+
+cpp_quote("#endif")
+
+const UINT D3D12_SHADER_COMPONENT_MAPPING_MASK = 0x7;
+const UINT D3D12_SHADER_COMPONENT_MAPPING_SHIFT = 3;
+const UINT D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES
+        = 1 << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 4);
+
+typedef enum D3D12_SHADER_MIN_PRECISION_SUPPORT
+{
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE = 0x0,
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_10_BIT = 0x1,
+    D3D12_SHADER_MIN_PRECISION_SUPPORT_16_BIT = 0x2,
+} D3D12_SHADER_MIN_PRECISION_SUPPORT;
+
+typedef enum D3D12_TILED_RESOURCES_TIER
+{
+    D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED = 0,
+    D3D12_TILED_RESOURCES_TIER_1 = 1,
+    D3D12_TILED_RESOURCES_TIER_2 = 2,
+    D3D12_TILED_RESOURCES_TIER_3 = 3,
+} D3D12_TILED_RESOURCES_TIER;
+
+typedef enum D3D12_RESOURCE_BINDING_TIER
+{
+    D3D12_RESOURCE_BINDING_TIER_1 = 1,
+    D3D12_RESOURCE_BINDING_TIER_2 = 2,
+    D3D12_RESOURCE_BINDING_TIER_3 = 3,
+} D3D12_RESOURCE_BINDING_TIER;
+
+typedef enum D3D12_CONSERVATIVE_RASTERIZATION_TIER
+{
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED = 0,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_1 = 1,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_2 = 2,
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER_3 = 3,
+} D3D12_CONSERVATIVE_RASTERIZATION_TIER;
+
+typedef enum D3D12_CROSS_NODE_SHARING_TIER
+{
+    D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED = 0,
+    D3D12_CROSS_NODE_SHARING_TIER_1_EMULATED = 1,
+    D3D12_CROSS_NODE_SHARING_TIER_1 = 2,
+    D3D12_CROSS_NODE_SHARING_TIER_2 = 3,
+} D3D12_CROSS_NODE_SHARING_TIER;
+
+typedef enum D3D12_RESOURCE_HEAP_TIER
+{
+    D3D12_RESOURCE_HEAP_TIER_1 = 1,
+    D3D12_RESOURCE_HEAP_TIER_2 = 2,
+} D3D12_RESOURCE_HEAP_TIER;
+
+typedef enum D3D12_FORMAT_SUPPORT1
+{
+    D3D12_FORMAT_SUPPORT1_NONE = 0x00000000,
+    D3D12_FORMAT_SUPPORT1_BUFFER = 0x00000001,
+    D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER = 0x00000002,
+    D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER = 0x00000004,
+    D3D12_FORMAT_SUPPORT1_SO_BUFFER = 0x00000008,
+    D3D12_FORMAT_SUPPORT1_TEXTURE1D = 0x00000010,
+    D3D12_FORMAT_SUPPORT1_TEXTURE2D = 0x00000020,
+    D3D12_FORMAT_SUPPORT1_TEXTURE3D = 0x00000040,
+    D3D12_FORMAT_SUPPORT1_TEXTURECUBE = 0x00000080,
+    D3D12_FORMAT_SUPPORT1_SHADER_LOAD = 0x00000100,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE = 0x00000200,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON = 0x00000400,
+    D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_MONO_TEXT = 0x00000800,
+    D3D12_FORMAT_SUPPORT1_MIP = 0x00001000,
+    D3D12_FORMAT_SUPPORT1_RENDER_TARGET = 0x00004000,
+    D3D12_FORMAT_SUPPORT1_BLENDABLE = 0x00008000,
+    D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL = 0x00010000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE = 0x00040000,
+    D3D12_FORMAT_SUPPORT1_DISPLAY = 0x00080000,
+    D3D12_FORMAT_SUPPORT1_CAST_WITHIN_BIT_LAYOUT = 0x00100000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET = 0x00200000,
+    D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD = 0x00400000,
+    D3D12_FORMAT_SUPPORT1_SHADER_GATHER = 0x00800000,
+    D3D12_FORMAT_SUPPORT1_BACK_BUFFER_CAST = 0x01000000,
+    D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW = 0x02000000,
+    D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON = 0x04000000,
+    D3D12_FORMAT_SUPPORT1_DECODER_OUTPUT = 0x08000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_OUTPUT = 0x10000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_INPUT = 0x20000000,
+    D3D12_FORMAT_SUPPORT1_VIDEO_ENCODER = 0x40000000,
+} D3D12_FORMAT_SUPPORT1;
+
+typedef enum D3D12_FORMAT_SUPPORT2
+{
+    D3D12_FORMAT_SUPPORT2_NONE = 0x00000000,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x00000001,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x00000002,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x00000004,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x00000008,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x00000010,
+    D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x00000020,
+    D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x00000040,
+    D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x00000080,
+    D3D12_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x00000100,
+    D3D12_FORMAT_SUPPORT2_TILED = 0x00000200,
+    D3D12_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x00004000,
+} D3D12_FORMAT_SUPPORT2;
+
+typedef enum D3D12_WRITEBUFFERIMMEDIATE_MODE
+{
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_DEFAULT = 0x0,
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_MARKER_IN = 0x1,
+    D3D12_WRITEBUFFERIMMEDIATE_MODE_MARKER_OUT = 0x2,
+} D3D12_WRITEBUFFERIMMEDIATE_MODE;
+
+typedef enum D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER
+{
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1 = 0x1,
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_2 = 0x2,
+}  D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER;
+
+typedef enum D3D12_SHADER_CACHE_SUPPORT_FLAGS
+{
+    D3D12_SHADER_CACHE_SUPPORT_NONE = 0x0,
+    D3D12_SHADER_CACHE_SUPPORT_SINGLE_PSO = 0x1,
+    D3D12_SHADER_CACHE_SUPPORT_LIBRARY = 0x2,
+    D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_INPROC_CACHE = 0x4,
+    D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_DISK_CACHE = 0x8,
+}  D3D12_SHADER_CACHE_SUPPORT_FLAGS;
+
+typedef enum D3D12_COMMAND_LIST_SUPPORT_FLAGS
+{
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0x0,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT = 0x1,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE = 0x2,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE = 0x4,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY = 0x8,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE = 0x10,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS = 0x20,
+    D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_ENCODE = 0x40,
+} D3D12_COMMAND_LIST_SUPPORT_FLAGS;
+
+typedef enum D3D12_VIEW_INSTANCING_TIER
+{
+    D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_VIEW_INSTANCING_TIER_1 = 0x1,
+    D3D12_VIEW_INSTANCING_TIER_2 = 0x2,
+    D3D12_VIEW_INSTANCING_TIER_3 = 0x3,
+}  D3D12_VIEW_INSTANCING_TIER;
+
+typedef enum D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER
+{
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0 = 0x0,
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_1 = 0x1,
+}  D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER;
+
+typedef enum D3D12_HEAP_SERIALIZATION_TIER
+{
+    D3D12_HEAP_SERIALIZATION_TIER_0 = 0x0,
+    D3D12_HEAP_SERIALIZATION_TIER_10 = 0xa,
+}  D3D12_HEAP_SERIALIZATION_TIER;
+
+typedef enum D3D12_RENDER_PASS_TIER
+{
+    D3D12_RENDER_PASS_TIER_0 = 0x0,
+    D3D12_RENDER_PASS_TIER_1 = 0x1,
+    D3D12_RENDER_PASS_TIER_2 = 0x2,
+} D3D12_RENDER_PASS_TIER;
+
+typedef enum D3D12_RAYTRACING_TIER
+{
+    D3D12_RAYTRACING_TIER_NOT_SUPPORTED = 0x0,
+    D3D12_RAYTRACING_TIER_1_0 = 0xa,
+} D3D12_RAYTRACING_TIER;
+
+interface ID3D12Fence;
+interface ID3D12RootSignature;
+interface ID3D12Heap;
+interface ID3D12DescriptorHeap;
+interface ID3D12Resource;
+interface ID3D12CommandAllocator;
+interface ID3D12GraphicsCommandList;
+interface ID3D12CommandQueue;
+interface ID3D12PipelineState;
+interface ID3D12Device;
+
+typedef RECT D3D12_RECT;
+
+typedef struct D3D12_BOX
+{
+    UINT left;
+    UINT top;
+    UINT front;
+    UINT right;
+    UINT bottom;
+    UINT back;
+} D3D12_BOX;
+
+typedef struct D3D12_VIEWPORT
+{
+    FLOAT TopLeftX;
+    FLOAT TopLeftY;
+    FLOAT Width;
+    FLOAT Height;
+    FLOAT MinDepth;
+    FLOAT MaxDepth;
+} D3D12_VIEWPORT;
+
+typedef struct D3D12_RANGE
+{
+    SIZE_T Begin;
+    SIZE_T End;
+} D3D12_RANGE;
+
+typedef struct D3D12_RANGE_UINT64
+{
+    UINT64 Begin;
+    UINT64 End;
+} D3D12_RANGE_UINT64;
+
+typedef struct D3D12_SUBRESOURCE_RANGE_UINT64
+{
+    UINT Subresource;
+    D3D12_RANGE_UINT64 Range;
+} D3D12_SUBRESOURCE_RANGE_UINT64;
+
+typedef struct D3D12_RESOURCE_ALLOCATION_INFO
+{
+    UINT64 SizeInBytes;
+    UINT64 Alignment;
+} D3D12_RESOURCE_ALLOCATION_INFO;
+
+typedef struct D3D12_DRAW_ARGUMENTS
+{
+    UINT VertexCountPerInstance;
+    UINT InstanceCount;
+    UINT StartVertexLocation;
+    UINT StartInstanceLocation;
+} D3D12_DRAW_ARGUMENTS;
+
+typedef struct D3D12_DRAW_INDEXED_ARGUMENTS
+{
+    UINT IndexCountPerInstance;
+    UINT InstanceCount;
+    UINT StartIndexLocation;
+    INT BaseVertexLocation;
+    UINT StartInstanceLocation;
+} D3D12_DRAW_INDEXED_ARGUMENTS;
+
+typedef struct D3D12_DISPATCH_ARGUMENTS
+{
+    UINT ThreadGroupCountX;
+    UINT ThreadGroupCountY;
+    UINT ThreadGroupCountZ;
+} D3D12_DISPATCH_ARGUMENTS;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS
+{
+    BOOL DoublePrecisionFloatShaderOps;
+    BOOL OutputMergerLogicOp;
+    D3D12_SHADER_MIN_PRECISION_SUPPORT MinPrecisionSupport;
+    D3D12_TILED_RESOURCES_TIER TiledResourcesTier;
+    D3D12_RESOURCE_BINDING_TIER ResourceBindingTier;
+    BOOL PSSpecifiedStencilRefSupported;
+    BOOL TypedUAVLoadAdditionalFormats;
+    BOOL ROVsSupported;
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER ConservativeRasterizationTier;
+    UINT MaxGPUVirtualAddressBitsPerResource;
+    BOOL StandardSwizzle64KBSupported;
+    D3D12_CROSS_NODE_SHARING_TIER CrossNodeSharingTier;
+    BOOL CrossAdapterRowMajorTextureSupported;
+    BOOL VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation;
+    D3D12_RESOURCE_HEAP_TIER ResourceHeapTier;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS;
+
+typedef struct D3D12_FEATURE_DATA_FORMAT_SUPPORT
+{
+    DXGI_FORMAT Format;
+    D3D12_FORMAT_SUPPORT1 Support1;
+    D3D12_FORMAT_SUPPORT2 Support2;
+} D3D12_FEATURE_DATA_FORMAT_SUPPORT;
+
+typedef enum D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS
+{
+    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE = 0x00000000,
+    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_TILED_RESOURCE = 0x00000001,
+} D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS;
+
+typedef struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS
+{
+    DXGI_FORMAT Format;
+    UINT SampleCount;
+    D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags;
+    UINT NumQualityLevels;
+} D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;
+
+typedef enum D3D12_HEAP_TYPE
+{
+    D3D12_HEAP_TYPE_DEFAULT = 1,
+    D3D12_HEAP_TYPE_UPLOAD = 2,
+    D3D12_HEAP_TYPE_READBACK = 3,
+    D3D12_HEAP_TYPE_CUSTOM = 4,
+} D3D12_HEAP_TYPE;
+
+typedef enum D3D12_CPU_PAGE_PROPERTY
+{
+    D3D12_CPU_PAGE_PROPERTY_UNKNOWN = 0,
+    D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE = 1,
+    D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE = 2,
+    D3D12_CPU_PAGE_PROPERTY_WRITE_BACK = 3,
+} D3D12_CPU_PAGE_PROPERTY;
+
+typedef enum D3D12_MEMORY_POOL
+{
+    D3D12_MEMORY_POOL_UNKNOWN = 0,
+    D3D12_MEMORY_POOL_L0 = 1,
+    D3D12_MEMORY_POOL_L1 = 2,
+} D3D12_MEMORY_POOL;
+
+typedef struct D3D12_HEAP_PROPERTIES
+{
+    D3D12_HEAP_TYPE Type;
+    D3D12_CPU_PAGE_PROPERTY CPUPageProperty;
+    D3D12_MEMORY_POOL MemoryPoolPreference;
+    UINT CreationNodeMask;
+    UINT VisibleNodeMask;
+} D3D12_HEAP_PROPERTIES;
+
+typedef enum D3D12_HEAP_FLAGS
+{
+    D3D12_HEAP_FLAG_NONE = 0x00,
+    D3D12_HEAP_FLAG_SHARED = 0x01,
+    D3D12_HEAP_FLAG_DENY_BUFFERS = 0x04,
+    D3D12_HEAP_FLAG_ALLOW_DISPLAY = 0x08,
+    D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER = 0x20,
+    D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES = 0x40,
+    D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES = 0x80,
+    D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES = 0x00,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS = 0xc0,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES = 0x44,
+    D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES = 0x84,
+} D3D12_HEAP_FLAGS;
+
+typedef struct D3D12_HEAP_DESC
+{
+    UINT64 SizeInBytes;
+    D3D12_HEAP_PROPERTIES Properties;
+    UINT64 Alignment;
+    D3D12_HEAP_FLAGS Flags;
+} D3D12_HEAP_DESC;
+
+typedef struct D3D12_TILED_RESOURCE_COORDINATE
+{
+    UINT X;
+    UINT Y;
+    UINT Z;
+    UINT Subresource;
+} D3D12_TILED_RESOURCE_COORDINATE;
+
+typedef struct D3D12_TILE_REGION_SIZE
+{
+    UINT NumTiles;
+    BOOL UseBox;
+    UINT Width;
+    UINT16 Height;
+    UINT16 Depth;
+} D3D12_TILE_REGION_SIZE;
+
+typedef struct D3D12_SUBRESOURCE_TILING
+{
+    UINT WidthInTiles;
+    UINT16 HeightInTiles;
+    UINT16 DepthInTiles;
+    UINT StartTileIndexInOverallResource;
+} D3D12_SUBRESOURCE_TILING;
+
+typedef struct D3D12_TILE_SHAPE
+{
+    UINT WidthInTexels;
+    UINT HeightInTexels;
+    UINT DepthInTexels;
+} D3D12_TILE_SHAPE;
+
+typedef struct D3D12_SHADER_BYTECODE
+{
+    const void *pShaderBytecode;
+    SIZE_T BytecodeLength;
+} D3D12_SHADER_BYTECODE;
+
+typedef struct D3D12_DEPTH_STENCIL_VALUE
+{
+    FLOAT Depth;
+    UINT8 Stencil;
+} D3D12_DEPTH_STENCIL_VALUE;
+
+typedef struct D3D12_CLEAR_VALUE
+{
+    DXGI_FORMAT Format;
+    union
+    {
+        FLOAT Color[4];
+        D3D12_DEPTH_STENCIL_VALUE DepthStencil;
+    };
+} D3D12_CLEAR_VALUE;
+
+typedef struct D3D12_PACKED_MIP_INFO
+{
+    UINT8 NumStandardMips;
+    UINT8 NumPackedMips;
+    UINT NumTilesForPackedMips;
+    UINT StartTileIndexInOverallResource;
+} D3D12_PACKED_MIP_INFO;
+
+typedef enum D3D12_RESOURCE_STATES
+{
+    D3D12_RESOURCE_STATE_COMMON = 0,
+    D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER = 0x1,
+    D3D12_RESOURCE_STATE_INDEX_BUFFER = 0x2,
+    D3D12_RESOURCE_STATE_RENDER_TARGET = 0x4,
+    D3D12_RESOURCE_STATE_UNORDERED_ACCESS = 0x8,
+    D3D12_RESOURCE_STATE_DEPTH_WRITE = 0x10,
+    D3D12_RESOURCE_STATE_DEPTH_READ = 0x20,
+    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE = 0x40,
+    D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE = 0x80,
+    D3D12_RESOURCE_STATE_STREAM_OUT = 0x100,
+    D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT = 0x200,
+    D3D12_RESOURCE_STATE_COPY_DEST = 0x400,
+    D3D12_RESOURCE_STATE_COPY_SOURCE = 0x800,
+    D3D12_RESOURCE_STATE_RESOLVE_DEST = 0x1000,
+    D3D12_RESOURCE_STATE_RESOLVE_SOURCE = 0x2000,
+    D3D12_RESOURCE_STATE_GENERIC_READ = 0x1 | 0x2 | 0x40 | 0x80 | 0x200 | 0x800,
+    D3D12_RESOURCE_STATE_PRESENT = 0x0,
+    D3D12_RESOURCE_STATE_PREDICATION = 0x200,
+} D3D12_RESOURCE_STATES;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_RESOURCE_STATES);")
+
+typedef enum D3D12_RESOURCE_BARRIER_TYPE
+{
+    D3D12_RESOURCE_BARRIER_TYPE_TRANSITION = 0,
+    D3D12_RESOURCE_BARRIER_TYPE_ALIASING = 1,
+    D3D12_RESOURCE_BARRIER_TYPE_UAV = 2,
+} D3D12_RESOURCE_BARRIER_TYPE;
+
+typedef enum D3D12_RESOURCE_BARRIER_FLAGS
+{
+    D3D12_RESOURCE_BARRIER_FLAG_NONE = 0x0,
+    D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY = 0x1,
+    D3D12_RESOURCE_BARRIER_FLAG_END_ONLY = 0x2,
+} D3D12_RESOURCE_BARRIER_FLAGS;
+
+typedef struct D3D12_RESOURCE_TRANSITION_BARRIER
+{
+    ID3D12Resource *pResource;
+    UINT Subresource;
+    D3D12_RESOURCE_STATES StateBefore;
+    D3D12_RESOURCE_STATES StateAfter;
+} D3D12_RESOURCE_TRANSITION_BARRIER;
+
+typedef struct D3D12_RESOURCE_ALIASING_BARRIER_ALIASING
+{
+    ID3D12Resource *pResourceBefore;
+    ID3D12Resource *pResourceAfter;
+} D3D12_RESOURCE_ALIASING_BARRIER;
+
+typedef struct D3D12_RESOURCE_UAV_BARRIER
+{
+    ID3D12Resource *pResource;
+} D3D12_RESOURCE_UAV_BARRIER;
+
+typedef struct D3D12_RESOURCE_BARRIER
+{
+    D3D12_RESOURCE_BARRIER_TYPE Type;
+    D3D12_RESOURCE_BARRIER_FLAGS Flags;
+    union
+    {
+        D3D12_RESOURCE_TRANSITION_BARRIER Transition;
+        D3D12_RESOURCE_ALIASING_BARRIER Aliasing;
+        D3D12_RESOURCE_UAV_BARRIER UAV;
+    };
+} D3D12_RESOURCE_BARRIER;
+
+typedef enum D3D12_RESOURCE_DIMENSION
+{
+    D3D12_RESOURCE_DIMENSION_UNKNOWN = 0,
+    D3D12_RESOURCE_DIMENSION_BUFFER = 1,
+    D3D12_RESOURCE_DIMENSION_TEXTURE1D = 2,
+    D3D12_RESOURCE_DIMENSION_TEXTURE2D = 3,
+    D3D12_RESOURCE_DIMENSION_TEXTURE3D = 4,
+} D3D12_RESOURCE_DIMENSION;
+
+typedef enum D3D12_TEXTURE_LAYOUT
+{
+    D3D12_TEXTURE_LAYOUT_UNKNOWN = 0,
+    D3D12_TEXTURE_LAYOUT_ROW_MAJOR = 1,
+    D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE = 2,
+    D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE = 3,
+} D3D12_TEXTURE_LAYOUT;
+
+typedef enum D3D12_RESOURCE_FLAGS
+{
+    D3D12_RESOURCE_FLAG_NONE = 0x0,
+    D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET = 0x1,
+    D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL = 0x2,
+    D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS = 0x4,
+    D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE = 0x8,
+    D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER = 0x10,
+    D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS = 0x20,
+} D3D12_RESOURCE_FLAGS;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_RESOURCE_FLAGS);")
+
+typedef struct D3D12_RESOURCE_DESC
+{
+    D3D12_RESOURCE_DIMENSION Dimension;
+    UINT64 Alignment;
+    UINT64 Width;
+    UINT Height;
+    UINT16 DepthOrArraySize;
+    UINT16 MipLevels;
+    DXGI_FORMAT Format;
+    DXGI_SAMPLE_DESC SampleDesc;
+    D3D12_TEXTURE_LAYOUT Layout;
+    D3D12_RESOURCE_FLAGS Flags;
+} D3D12_RESOURCE_DESC;
+
+typedef enum D3D12_RESOLVE_MODE
+{
+    D3D12_RESOLVE_MODE_DECOMPRESS = 0,
+    D3D12_RESOLVE_MODE_MIN = 1,
+    D3D12_RESOLVE_MODE_MAX = 2,
+    D3D12_RESOLVE_MODE_AVERAGE = 3,
+} D3D12_RESOLVE_MODE;
+
+typedef struct D3D12_SAMPLE_POSITION
+{
+    INT8 X;
+    INT8 Y;
+} D3D12_SAMPLE_POSITION;
+
+typedef enum D3D12_TEXTURE_COPY_TYPE
+{
+    D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX = 0,
+    D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT = 1,
+} D3D12_TEXTURE_COPY_TYPE;
+
+typedef struct D3D12_SUBRESOURCE_FOOTPRINT
+{
+    DXGI_FORMAT Format;
+    UINT Width;
+    UINT Height;
+    UINT Depth;
+    UINT RowPitch;
+} D3D12_SUBRESOURCE_FOOTPRINT;
+
+typedef struct D3D12_PLACED_SUBRESOURCE_FOOTPRINT
+{
+    UINT64 Offset;
+    D3D12_SUBRESOURCE_FOOTPRINT Footprint;
+} D3D12_PLACED_SUBRESOURCE_FOOTPRINT;
+
+typedef struct D3D12_TEXTURE_COPY_LOCATION
+{
+    ID3D12Resource *pResource;
+    D3D12_TEXTURE_COPY_TYPE Type;
+    union
+    {
+        D3D12_PLACED_SUBRESOURCE_FOOTPRINT PlacedFootprint;
+        UINT SubresourceIndex;
+    };
+} D3D12_TEXTURE_COPY_LOCATION;
+
+typedef enum D3D12_DESCRIPTOR_RANGE_TYPE
+{
+    D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0,
+    D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1,
+    D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2,
+    D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3,
+} D3D12_DESCRIPTOR_RANGE_TYPE;
+
+typedef struct D3D12_DESCRIPTOR_RANGE
+{
+    D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
+    UINT NumDescriptors;
+    UINT BaseShaderRegister;
+    UINT RegisterSpace;
+    UINT OffsetInDescriptorsFromTableStart;
+} D3D12_DESCRIPTOR_RANGE;
+
+typedef enum D3D12_DESCRIPTOR_RANGE_FLAGS
+{
+    D3D12_DESCRIPTOR_RANGE_FLAG_NONE = 0x0,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE = 0x1,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE = 0x2,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC = 0x8,
+} D3D12_DESCRIPTOR_RANGE_FLAGS;
+
+typedef struct D3D12_DESCRIPTOR_RANGE1
+{
+    D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
+    UINT NumDescriptors;
+    UINT BaseShaderRegister;
+    UINT RegisterSpace;
+    D3D12_DESCRIPTOR_RANGE_FLAGS Flags;
+    UINT OffsetInDescriptorsFromTableStart;
+} D3D12_DESCRIPTOR_RANGE1;
+
+typedef struct D3D12_ROOT_DESCRIPTOR_TABLE
+{
+    UINT NumDescriptorRanges;
+    const D3D12_DESCRIPTOR_RANGE *pDescriptorRanges;
+} D3D12_ROOT_DESCRIPTOR_TABLE;
+
+typedef struct D3D12_ROOT_DESCRIPTOR_TABLE1
+{
+    UINT NumDescriptorRanges;
+    const D3D12_DESCRIPTOR_RANGE1 *pDescriptorRanges;
+} D3D12_ROOT_DESCRIPTOR_TABLE1;
+
+typedef struct D3D12_ROOT_CONSTANTS
+{
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    UINT Num32BitValues;
+} D3D12_ROOT_CONSTANTS;
+
+typedef struct D3D12_ROOT_DESCRIPTOR
+{
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+} D3D12_ROOT_DESCRIPTOR;
+
+typedef enum D3D12_ROOT_DESCRIPTOR_FLAGS
+{
+    D3D12_ROOT_DESCRIPTOR_FLAG_NONE = 0x0,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE = 0x2,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC = 0x8,
+} D3D12_ROOT_DESCRIPTOR_FLAGS;
+
+typedef struct D3D12_ROOT_DESCRIPTOR1
+{
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    D3D12_ROOT_DESCRIPTOR_FLAGS Flags;
+} D3D12_ROOT_DESCRIPTOR1;
+
+typedef enum D3D12_ROOT_PARAMETER_TYPE
+{
+    D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE = 0,
+    D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS = 1,
+    D3D12_ROOT_PARAMETER_TYPE_CBV = 2,
+    D3D12_ROOT_PARAMETER_TYPE_SRV = 3,
+    D3D12_ROOT_PARAMETER_TYPE_UAV = 4,
+} D3D12_ROOT_PARAMETER_TYPE;
+
+typedef enum D3D12_SHADER_VISIBILITY
+{
+    D3D12_SHADER_VISIBILITY_ALL = 0,
+    D3D12_SHADER_VISIBILITY_VERTEX = 1,
+    D3D12_SHADER_VISIBILITY_HULL = 2,
+    D3D12_SHADER_VISIBILITY_DOMAIN = 3,
+    D3D12_SHADER_VISIBILITY_GEOMETRY = 4,
+    D3D12_SHADER_VISIBILITY_PIXEL = 5,
+} D3D12_SHADER_VISIBILITY;
+
+typedef struct D3D12_ROOT_PARAMETER
+{
+    D3D12_ROOT_PARAMETER_TYPE ParameterType;
+    union
+    {
+        D3D12_ROOT_DESCRIPTOR_TABLE DescriptorTable;
+        D3D12_ROOT_CONSTANTS Constants;
+        D3D12_ROOT_DESCRIPTOR Descriptor;
+    };
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_ROOT_PARAMETER;
+
+typedef struct D3D12_ROOT_PARAMETER1
+{
+    D3D12_ROOT_PARAMETER_TYPE ParameterType;
+    union
+    {
+        D3D12_ROOT_DESCRIPTOR_TABLE1 DescriptorTable;
+        D3D12_ROOT_CONSTANTS Constants;
+        D3D12_ROOT_DESCRIPTOR1 Descriptor;
+    };
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_ROOT_PARAMETER1;
+
+typedef enum D3D12_STATIC_BORDER_COLOR
+{
+    D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK = 0,
+    D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK = 1,
+    D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE = 2,
+} D3D12_STATIC_BORDER_COLOR;
+
+typedef enum D3D12_FILTER
+{
+    D3D12_FILTER_MIN_MAG_MIP_POINT = 0x00,
+    D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x01,
+    D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x04,
+    D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x05,
+    D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10,
+    D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11,
+    D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14,
+    D3D12_FILTER_MIN_MAG_MIP_LINEAR = 0x15,
+    D3D12_FILTER_ANISOTROPIC = 0x55,
+    D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80,
+    D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81,
+    D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84,
+    D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85,
+    D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90,
+    D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91,
+    D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94,
+    D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95,
+    D3D12_FILTER_COMPARISON_ANISOTROPIC = 0xd5,
+    D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT = 0x100,
+    D3D12_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x101,
+    D3D12_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x104,
+    D3D12_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x105,
+    D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x110,
+    D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x111,
+    D3D12_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x114,
+    D3D12_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR = 0x115,
+    D3D12_FILTER_MINIMUM_ANISOTROPIC = 0x155,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT = 0x180,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x181,
+    D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x184,
+    D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x185,
+    D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x190,
+    D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x191,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x194,
+    D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR = 0x195,
+    D3D12_FILTER_MAXIMUM_ANISOTROPIC = 0x1d5,
+} D3D12_FILTER;
+
+typedef enum D3D12_FILTER_TYPE
+{
+    D3D12_FILTER_TYPE_POINT = 0,
+    D3D12_FILTER_TYPE_LINEAR = 1,
+} D3D12_FILTER_TYPE;
+
+const UINT D3D12_MIP_FILTER_SHIFT = 0;
+const UINT D3D12_MAG_FILTER_SHIFT = 2;
+const UINT D3D12_MIN_FILTER_SHIFT = 4;
+const UINT D3D12_FILTER_TYPE_MASK = 0x3;
+
+const UINT D3D12_ANISOTROPIC_FILTERING_BIT = 0x40;
+
+typedef enum D3D12_FILTER_REDUCTION_TYPE
+{
+    D3D12_FILTER_REDUCTION_TYPE_STANDARD = 0,
+    D3D12_FILTER_REDUCTION_TYPE_COMPARISON = 1,
+    D3D12_FILTER_REDUCTION_TYPE_MINIMUM = 2,
+    D3D12_FILTER_REDUCTION_TYPE_MAXIMUM = 3,
+} D3D12_FILTER_REDUCTION_TYPE;
+
+const UINT D3D12_FILTER_REDUCTION_TYPE_MASK = 0x3;
+const UINT D3D12_FILTER_REDUCTION_TYPE_SHIFT = 7;
+
+cpp_quote("#define D3D12_DECODE_MAG_FILTER(filter) \\")
+cpp_quote("    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MAG_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))")
+
+cpp_quote("#define D3D12_DECODE_MIN_FILTER(filter) \\")
+cpp_quote("    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MIN_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))")
+
+cpp_quote("#define D3D12_DECODE_MIP_FILTER(filter) \\")
+cpp_quote("    ((D3D12_FILTER_TYPE)(((filter) >> D3D12_MIP_FILTER_SHIFT) & D3D12_FILTER_TYPE_MASK))")
+
+cpp_quote("#define D3D12_DECODE_IS_ANISOTROPIC_FILTER(filter)  \\")
+cpp_quote("    (((filter) & D3D12_ANISOTROPIC_FILTERING_BIT) \\")
+cpp_quote("    && (D3D12_DECODE_MIN_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR) \\")
+cpp_quote("    && (D3D12_DECODE_MAG_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR) \\")
+cpp_quote("    && (D3D12_DECODE_MIP_FILTER(filter) == D3D12_FILTER_TYPE_LINEAR))")
+
+cpp_quote("#define D3D12_DECODE_FILTER_REDUCTION(filter) \\")
+cpp_quote("    ((D3D12_FILTER_REDUCTION_TYPE)(((filter) >> D3D12_FILTER_REDUCTION_TYPE_SHIFT) \\")
+cpp_quote("    & D3D12_FILTER_REDUCTION_TYPE_MASK))")
+
+cpp_quote("#define D3D12_DECODE_IS_COMPARISON_FILTER(filter) \\")
+cpp_quote("    (D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_COMPARISON)")
+
+typedef enum D3D12_TEXTURE_ADDRESS_MODE
+{
+    D3D12_TEXTURE_ADDRESS_MODE_WRAP = 1,
+    D3D12_TEXTURE_ADDRESS_MODE_MIRROR = 2,
+    D3D12_TEXTURE_ADDRESS_MODE_CLAMP = 3,
+    D3D12_TEXTURE_ADDRESS_MODE_BORDER = 4,
+    D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE = 5,
+} D3D12_TEXTURE_ADDRESS_MODE;
+
+typedef enum D3D12_COMPARISON_FUNC
+{
+    D3D12_COMPARISON_FUNC_NEVER = 1,
+    D3D12_COMPARISON_FUNC_LESS = 2,
+    D3D12_COMPARISON_FUNC_EQUAL = 3,
+    D3D12_COMPARISON_FUNC_LESS_EQUAL = 4,
+    D3D12_COMPARISON_FUNC_GREATER = 5,
+    D3D12_COMPARISON_FUNC_NOT_EQUAL = 6,
+    D3D12_COMPARISON_FUNC_GREATER_EQUAL = 7,
+    D3D12_COMPARISON_FUNC_ALWAYS = 8,
+} D3D12_COMPARISON_FUNC;
+
+typedef struct D3D12_STATIC_SAMPLER_DESC
+{
+    D3D12_FILTER Filter;
+    D3D12_TEXTURE_ADDRESS_MODE AddressU;
+    D3D12_TEXTURE_ADDRESS_MODE AddressV;
+    D3D12_TEXTURE_ADDRESS_MODE AddressW;
+    FLOAT MipLODBias;
+    UINT MaxAnisotropy;
+    D3D12_COMPARISON_FUNC ComparisonFunc;
+    D3D12_STATIC_BORDER_COLOR BorderColor;
+    FLOAT MinLOD;
+    FLOAT MaxLOD;
+    UINT ShaderRegister;
+    UINT RegisterSpace;
+    D3D12_SHADER_VISIBILITY ShaderVisibility;
+} D3D12_STATIC_SAMPLER_DESC;
+
+typedef enum D3D12_ROOT_SIGNATURE_FLAGS
+{
+    D3D12_ROOT_SIGNATURE_FLAG_NONE = 0x00,
+    D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x01,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS = 0x02,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS = 0x04,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x08,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10,
+    D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20,
+    D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT = 0x40,
+} D3D12_ROOT_SIGNATURE_FLAGS;
+
+typedef struct D3D12_ROOT_SIGNATURE_DESC
+{
+    UINT NumParameters;
+    const D3D12_ROOT_PARAMETER *pParameters;
+    UINT NumStaticSamplers;
+    const D3D12_STATIC_SAMPLER_DESC *pStaticSamplers;
+    D3D12_ROOT_SIGNATURE_FLAGS Flags;
+} D3D12_ROOT_SIGNATURE_DESC;
+
+typedef struct D3D12_ROOT_SIGNATURE_DESC1
+{
+    UINT NumParameters;
+    const D3D12_ROOT_PARAMETER1 *pParameters;
+    UINT NumStaticSamplers;
+    const D3D12_STATIC_SAMPLER_DESC *pStaticSamplers;
+    D3D12_ROOT_SIGNATURE_FLAGS Flags;
+} D3D12_ROOT_SIGNATURE_DESC1;
+
+typedef enum D3D_ROOT_SIGNATURE_VERSION
+{
+    D3D_ROOT_SIGNATURE_VERSION_1 = 0x1,
+    D3D_ROOT_SIGNATURE_VERSION_1_0 = 0x1,
+    D3D_ROOT_SIGNATURE_VERSION_1_1 = 0x2,
+} D3D_ROOT_SIGNATURE_VERSION;
+
+typedef struct D3D12_VERSIONED_ROOT_SIGNATURE_DESC
+{
+    D3D_ROOT_SIGNATURE_VERSION Version;
+    union
+    {
+        D3D12_ROOT_SIGNATURE_DESC Desc_1_0;
+        D3D12_ROOT_SIGNATURE_DESC1 Desc_1_1;
+    };
+} D3D12_VERSIONED_ROOT_SIGNATURE_DESC;
+
+typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
+{
+    D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
+    D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
+    D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
+    D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
+    D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES,
+} D3D12_DESCRIPTOR_HEAP_TYPE;
+
+typedef enum D3D12_DESCRIPTOR_HEAP_FLAGS
+{
+    D3D12_DESCRIPTOR_HEAP_FLAG_NONE = 0x0,
+    D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE = 0x1,
+} D3D12_DESCRIPTOR_HEAP_FLAGS;
+
+typedef struct D3D12_DESCRIPTOR_HEAP_DESC
+{
+    D3D12_DESCRIPTOR_HEAP_TYPE Type;
+    UINT NumDescriptors;
+    D3D12_DESCRIPTOR_HEAP_FLAGS Flags;
+    UINT NodeMask;
+} D3D12_DESCRIPTOR_HEAP_DESC;
+
+typedef UINT64 D3D12_GPU_VIRTUAL_ADDRESS;
+
+typedef struct D3D12_CONSTANT_BUFFER_VIEW_DESC
+{
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+} D3D12_CONSTANT_BUFFER_VIEW_DESC;
+
+typedef enum D3D12_SRV_DIMENSION
+{
+    D3D12_SRV_DIMENSION_UNKNOWN = 0,
+    D3D12_SRV_DIMENSION_BUFFER = 1,
+    D3D12_SRV_DIMENSION_TEXTURE1D = 2,
+    D3D12_SRV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_SRV_DIMENSION_TEXTURE2D = 4,
+    D3D12_SRV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_SRV_DIMENSION_TEXTURE2DMS = 6,
+    D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
+    D3D12_SRV_DIMENSION_TEXTURE3D = 8,
+    D3D12_SRV_DIMENSION_TEXTURECUBE = 9,
+    D3D12_SRV_DIMENSION_TEXTURECUBEARRAY = 10,
+} D3D12_SRV_DIMENSION;
+
+typedef enum D3D12_BUFFER_SRV_FLAGS
+{
+    D3D12_BUFFER_SRV_FLAG_NONE = 0x0,
+    D3D12_BUFFER_SRV_FLAG_RAW = 0x1,
+} D3D12_BUFFER_SRV_FLAGS;
+
+typedef enum D3D12_SHADER_COMPONENT_MAPPING
+{
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 = 0,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1 = 1,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2 = 2,
+    D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3 = 3,
+    D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0 = 4,
+    D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1 = 5,
+} D3D12_SHADER_COMPONENT_MAPPING;
+
+cpp_quote("#define D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(x, y, z, w) \\")
+cpp_quote("        (((x) & D3D12_SHADER_COMPONENT_MAPPING_MASK) \\")
+cpp_quote("        | (((y) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << D3D12_SHADER_COMPONENT_MAPPING_SHIFT) \\")
+cpp_quote("        | (((z) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 2)) \\")
+cpp_quote("        | (((w) & D3D12_SHADER_COMPONENT_MAPPING_MASK) << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 3)) \\")
+cpp_quote("        | D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES)")
+cpp_quote("#define D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, 3)")
+
+cpp_quote("#define D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(i, mapping) \\")
+cpp_quote("        ((D3D12_SHADER_COMPONENT_MAPPING)(mapping >> (i * D3D12_SHADER_COMPONENT_MAPPING_SHIFT) \\")
+cpp_quote("        & D3D12_SHADER_COMPONENT_MAPPING_MASK))")
+
+typedef struct D3D12_BUFFER_SRV
+{
+    UINT64 FirstElement;
+    UINT NumElements;
+    UINT StructureByteStride;
+    D3D12_BUFFER_SRV_FLAGS Flags;
+} D3D12_BUFFER_SRV;
+
+typedef struct D3D12_TEX1D_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX1D_SRV;
+
+typedef struct D3D12_TEX1D_ARRAY_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX1D_ARRAY_SRV;
+
+typedef struct D3D12_TEX2D_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT PlaneSlice;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX2D_SRV;
+
+typedef struct D3D12_TEX2D_ARRAY_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX2D_ARRAY_SRV;
+
+typedef struct D3D12_TEX2DMS_SRV
+{
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_SRV;
+
+typedef struct D3D12_TEX2DMS_ARRAY_SRV
+{
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_SRV;
+
+typedef struct D3D12_TEX3D_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEX3D_SRV;
+
+typedef struct D3D12_TEXCUBE_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEXCUBE_SRV;
+
+typedef struct D3D12_TEXCUBE_ARRAY_SRV
+{
+    UINT MostDetailedMip;
+    UINT MipLevels;
+    UINT First2DArrayFace;
+    UINT NumCubes;
+    FLOAT ResourceMinLODClamp;
+} D3D12_TEXCUBE_ARRAY_SRV;
+
+typedef struct D3D12_SHADER_RESOURCE_VIEW_DESC
+{
+    DXGI_FORMAT Format;
+    D3D12_SRV_DIMENSION ViewDimension;
+    UINT Shader4ComponentMapping;
+    union
+    {
+        D3D12_BUFFER_SRV Buffer;
+        D3D12_TEX1D_SRV Texture1D;
+        D3D12_TEX1D_ARRAY_SRV Texture1DArray;
+        D3D12_TEX2D_SRV Texture2D;
+        D3D12_TEX2D_ARRAY_SRV Texture2DArray;
+        D3D12_TEX2DMS_SRV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_SRV Texture2DMSArray;
+        D3D12_TEX3D_SRV Texture3D;
+        D3D12_TEXCUBE_SRV TextureCube;
+        D3D12_TEXCUBE_ARRAY_SRV TextureCubeArray;
+    };
+} D3D12_SHADER_RESOURCE_VIEW_DESC;
+
+typedef enum D3D12_UAV_DIMENSION
+{
+    D3D12_UAV_DIMENSION_UNKNOWN = 0,
+    D3D12_UAV_DIMENSION_BUFFER = 1,
+    D3D12_UAV_DIMENSION_TEXTURE1D = 2,
+    D3D12_UAV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_UAV_DIMENSION_TEXTURE2D = 4,
+    D3D12_UAV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_UAV_DIMENSION_TEXTURE3D = 8,
+} D3D12_UAV_DIMENSION;
+
+typedef enum D3D12_BUFFER_UAV_FLAGS
+{
+    D3D12_BUFFER_UAV_FLAG_NONE = 0x0,
+    D3D12_BUFFER_UAV_FLAG_RAW = 0x1,
+} D3D12_BUFFER_UAV_FLAGS;
+
+typedef struct D3D12_BUFFER_UAV
+{
+    UINT64 FirstElement;
+    UINT NumElements;
+    UINT StructureByteStride;
+    UINT64 CounterOffsetInBytes;
+    D3D12_BUFFER_UAV_FLAGS Flags;
+} D3D12_BUFFER_UAV;
+
+typedef struct D3D12_TEX1D_UAV
+{
+    UINT MipSlice;
+} D3D12_TEX1D_UAV;
+
+typedef struct D3D12_TEX1D_ARRAY_UAV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_UAV;
+
+typedef struct D3D12_TEX2D_UAV
+{
+    UINT MipSlice;
+    UINT PlaneSlice;
+} D3D12_TEX2D_UAV;
+
+typedef struct D3D12_TEX2D_ARRAY_UAV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+} D3D12_TEX2D_ARRAY_UAV;
+
+typedef struct D3D12_TEX3D_UAV
+{
+    UINT MipSlice;
+    UINT FirstWSlice;
+    UINT WSize;
+} D3D12_TEX3D_UAV;
+
+typedef struct D3D12_UNORDERED_ACCESS_VIEW_DESC
+{
+    DXGI_FORMAT Format;
+    D3D12_UAV_DIMENSION ViewDimension;
+    union
+    {
+        D3D12_BUFFER_UAV Buffer;
+        D3D12_TEX1D_UAV Texture1D;
+        D3D12_TEX1D_ARRAY_UAV Texture1DArray;
+        D3D12_TEX2D_UAV Texture2D;
+        D3D12_TEX2D_ARRAY_UAV Texture2DArray;
+        D3D12_TEX3D_UAV Texture3D;
+    };
+} D3D12_UNORDERED_ACCESS_VIEW_DESC;
+
+typedef enum D3D12_RTV_DIMENSION
+{
+    D3D12_RTV_DIMENSION_UNKNOWN = 0,
+    D3D12_RTV_DIMENSION_BUFFER = 1,
+    D3D12_RTV_DIMENSION_TEXTURE1D = 2,
+    D3D12_RTV_DIMENSION_TEXTURE1DARRAY = 3,
+    D3D12_RTV_DIMENSION_TEXTURE2D = 4,
+    D3D12_RTV_DIMENSION_TEXTURE2DARRAY = 5,
+    D3D12_RTV_DIMENSION_TEXTURE2DMS = 6,
+    D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY = 7,
+    D3D12_RTV_DIMENSION_TEXTURE3D = 8,
+} D3D12_RTV_DIMENSION;
+
+typedef struct D3D12_BUFFER_RTV
+{
+    UINT64 FirstElement;
+    UINT NumElements;
+} D3D12_BUFFER_RTV;
+
+typedef struct D3D12_TEX1D_RTV
+{
+    UINT MipSlice;
+} D3D12_TEX1D_RTV;
+
+typedef struct D3D12_TEX1D_ARRAY_RTV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_RTV;
+
+typedef struct D3D12_TEX2D_RTV
+{
+    UINT MipSlice;
+    UINT PlaneSlice;
+} D3D12_TEX2D_RTV;
+
+typedef struct D3D12_TEX2D_ARRAY_RTV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+    UINT PlaneSlice;
+} D3D12_TEX2D_ARRAY_RTV;
+
+typedef struct D3D12_TEX2DMS_RTV
+{
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_RTV;
+
+typedef struct D3D12_TEX2DMS_ARRAY_RTV
+{
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_RTV;
+
+typedef struct D3D12_TEX3D_RTV
+{
+    UINT MipSlice;
+    UINT FirstWSlice;
+    UINT WSize;
+} D3D12_TEX3D_RTV;
+
+typedef struct D3D12_RENDER_TARGET_VIEW_DESC
+{
+    DXGI_FORMAT Format;
+    D3D12_RTV_DIMENSION ViewDimension;
+    union
+    {
+        D3D12_BUFFER_RTV Buffer;
+        D3D12_TEX1D_RTV Texture1D;
+        D3D12_TEX1D_ARRAY_RTV Texture1DArray;
+        D3D12_TEX2D_RTV Texture2D;
+        D3D12_TEX2D_ARRAY_RTV Texture2DArray;
+        D3D12_TEX2DMS_RTV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_RTV Texture2DMSArray;
+        D3D12_TEX3D_RTV Texture3D;
+    };
+} D3D12_RENDER_TARGET_VIEW_DESC;
+
+typedef enum D3D12_DSV_DIMENSION
+{
+    D3D12_DSV_DIMENSION_UNKNOWN = 0,
+    D3D12_DSV_DIMENSION_TEXTURE1D = 1,
+    D3D12_DSV_DIMENSION_TEXTURE1DARRAY = 2,
+    D3D12_DSV_DIMENSION_TEXTURE2D = 3,
+    D3D12_DSV_DIMENSION_TEXTURE2DARRAY = 4,
+    D3D12_DSV_DIMENSION_TEXTURE2DMS = 5,
+    D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY = 6,
+} D3D12_DSV_DIMENSION;
+
+typedef enum D3D12_DSV_FLAGS
+{
+    D3D12_DSV_FLAG_NONE = 0x0,
+    D3D12_DSV_FLAG_READ_ONLY_DEPTH = 0x1,
+    D3D12_DSV_FLAG_READ_ONLY_STENCIL = 0x2,
+} D3D12_DSV_FLAGS;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_DSV_FLAGS);")
+
+typedef struct D3D12_TEX1D_DSV
+{
+    UINT MipSlice;
+} D3D12_TEX1D_DSV;
+
+typedef struct D3D12_TEX1D_ARRAY_DSV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX1D_ARRAY_DSV;
+
+typedef struct D3D12_TEX2D_DSV
+{
+    UINT MipSlice;
+} D3D12_TEX2D_DSV;
+
+typedef struct D3D12_TEX2D_ARRAY_DSV
+{
+    UINT MipSlice;
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2D_ARRAY_DSV;
+
+typedef struct D3D12_TEX2DMS_DSV
+{
+    UINT UnusedField_NothingToDefine;
+} D3D12_TEX2DMS_DSV;
+
+typedef struct D3D12_TEX2DMS_ARRAY_DSV
+{
+    UINT FirstArraySlice;
+    UINT ArraySize;
+} D3D12_TEX2DMS_ARRAY_DSV;
+
+typedef struct D3D12_DEPTH_STENCIL_VIEW_DESC
+{
+    DXGI_FORMAT Format;
+    D3D12_DSV_DIMENSION ViewDimension;
+    D3D12_DSV_FLAGS Flags;
+    union
+    {
+        D3D12_TEX1D_DSV Texture1D;
+        D3D12_TEX1D_ARRAY_DSV Texture1DArray;
+        D3D12_TEX2D_DSV Texture2D;
+        D3D12_TEX2D_ARRAY_DSV Texture2DArray;
+        D3D12_TEX2DMS_DSV Texture2DMS;
+        D3D12_TEX2DMS_ARRAY_DSV Texture2DMSArray;
+    };
+} D3D12_DEPTH_STENCIL_VIEW_DESC;
+
+typedef struct D3D12_SAMPLER_DESC
+{
+    D3D12_FILTER Filter;
+    D3D12_TEXTURE_ADDRESS_MODE AddressU;
+    D3D12_TEXTURE_ADDRESS_MODE AddressV;
+    D3D12_TEXTURE_ADDRESS_MODE AddressW;
+    FLOAT MipLODBias;
+    UINT MaxAnisotropy;
+    D3D12_COMPARISON_FUNC ComparisonFunc;
+    FLOAT BorderColor[4];
+    FLOAT MinLOD;
+    FLOAT MaxLOD;
+} D3D12_SAMPLER_DESC;
+
+typedef struct D3D12_CPU_DESCRIPTOR_HANDLE
+{
+    SIZE_T ptr;
+} D3D12_CPU_DESCRIPTOR_HANDLE;
+
+typedef struct D3D12_GPU_DESCRIPTOR_HANDLE
+{
+    UINT64 ptr;
+} D3D12_GPU_DESCRIPTOR_HANDLE;
+
+typedef enum D3D12_STENCIL_OP
+{
+    D3D12_STENCIL_OP_KEEP = 1,
+    D3D12_STENCIL_OP_ZERO = 2,
+    D3D12_STENCIL_OP_REPLACE = 3,
+    D3D12_STENCIL_OP_INCR_SAT = 4,
+    D3D12_STENCIL_OP_DECR_SAT = 5,
+    D3D12_STENCIL_OP_INVERT = 6,
+    D3D12_STENCIL_OP_INCR = 7,
+    D3D12_STENCIL_OP_DECR = 8,
+} D3D12_STENCIL_OP;
+
+typedef struct D3D12_DEPTH_STENCILOP_DESC
+{
+    D3D12_STENCIL_OP StencilFailOp;
+    D3D12_STENCIL_OP StencilDepthFailOp;
+    D3D12_STENCIL_OP StencilPassOp;
+    D3D12_COMPARISON_FUNC StencilFunc;
+} D3D12_DEPTH_STENCILOP_DESC;
+
+typedef enum D3D12_DEPTH_WRITE_MASK
+{
+    D3D12_DEPTH_WRITE_MASK_ZERO = 0,
+    D3D12_DEPTH_WRITE_MASK_ALL = 1,
+} D3D12_DEPTH_WRITE_MASK;
+
+typedef struct D3D12_DEPTH_STENCIL_DESC
+{
+    BOOL DepthEnable;
+    D3D12_DEPTH_WRITE_MASK DepthWriteMask;
+    D3D12_COMPARISON_FUNC DepthFunc;
+    BOOL StencilEnable;
+    UINT8 StencilReadMask;
+    UINT8 StencilWriteMask;
+    D3D12_DEPTH_STENCILOP_DESC FrontFace;
+    D3D12_DEPTH_STENCILOP_DESC BackFace;
+} D3D12_DEPTH_STENCIL_DESC;
+
+typedef enum D3D12_BLEND
+{
+    D3D12_BLEND_ZERO = 1,
+    D3D12_BLEND_ONE = 2,
+    D3D12_BLEND_SRC_COLOR = 3,
+    D3D12_BLEND_INV_SRC_COLOR = 4,
+    D3D12_BLEND_SRC_ALPHA = 5,
+    D3D12_BLEND_INV_SRC_ALPHA = 6,
+    D3D12_BLEND_DEST_ALPHA = 7,
+    D3D12_BLEND_INV_DEST_ALPHA = 8,
+    D3D12_BLEND_DEST_COLOR = 9,
+    D3D12_BLEND_INV_DEST_COLOR = 10,
+    D3D12_BLEND_SRC_ALPHA_SAT = 11,
+    D3D12_BLEND_BLEND_FACTOR = 14,
+    D3D12_BLEND_INV_BLEND_FACTOR = 15,
+    D3D12_BLEND_SRC1_COLOR = 16,
+    D3D12_BLEND_INV_SRC1_COLOR = 17,
+    D3D12_BLEND_SRC1_ALPHA = 18,
+    D3D12_BLEND_INV_SRC1_ALPHA = 19,
+} D3D12_BLEND;
+
+typedef enum D3D12_BLEND_OP
+{
+    D3D12_BLEND_OP_ADD = 1,
+    D3D12_BLEND_OP_SUBTRACT = 2,
+    D3D12_BLEND_OP_REV_SUBTRACT = 3,
+    D3D12_BLEND_OP_MIN = 4,
+    D3D12_BLEND_OP_MAX = 5,
+} D3D12_BLEND_OP;
+
+typedef enum D3D12_LOGIC_OP
+{
+    D3D12_LOGIC_OP_CLEAR = 0,
+    D3D12_LOGIC_OP_SET = 1,
+    D3D12_LOGIC_OP_COPY = 2,
+    D3D12_LOGIC_OP_COPY_INVERTED = 3,
+    D3D12_LOGIC_OP_NOOP = 4,
+} D3D12_LOGIC_OP;
+
+typedef enum D3D12_COLOR_WRITE_ENABLE
+{
+    D3D12_COLOR_WRITE_ENABLE_RED = 0x1,
+    D3D12_COLOR_WRITE_ENABLE_GREEN = 0x2,
+    D3D12_COLOR_WRITE_ENABLE_BLUE = 0x4,
+    D3D12_COLOR_WRITE_ENABLE_ALPHA = 0x8,
+    D3D12_COLOR_WRITE_ENABLE_ALL = (D3D12_COLOR_WRITE_ENABLE_RED\
+            | D3D12_COLOR_WRITE_ENABLE_GREEN | D3D12_COLOR_WRITE_ENABLE_BLUE\
+            | D3D12_COLOR_WRITE_ENABLE_ALPHA),
+} D3D12_COLOR_WRITE_ENABLE;
+
+typedef struct D3D12_RENDER_TARGET_BLEND_DESC
+{
+    BOOL BlendEnable;
+    BOOL LogicOpEnable;
+    D3D12_BLEND SrcBlend;
+    D3D12_BLEND DestBlend;
+    D3D12_BLEND_OP BlendOp;
+    D3D12_BLEND SrcBlendAlpha;
+    D3D12_BLEND DestBlendAlpha;
+    D3D12_BLEND_OP BlendOpAlpha;
+    D3D12_LOGIC_OP LogicOp;
+    UINT8 RenderTargetWriteMask;
+} D3D12_RENDER_TARGET_BLEND_DESC;
+
+typedef struct D3D12_BLEND_DESC
+{
+    BOOL AlphaToCoverageEnable;
+    BOOL IndependentBlendEnable;
+    D3D12_RENDER_TARGET_BLEND_DESC RenderTarget[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+} D3D12_BLEND_DESC;
+
+typedef enum D3D12_FILL_MODE
+{
+    D3D12_FILL_MODE_WIREFRAME = 2,
+    D3D12_FILL_MODE_SOLID = 3,
+} D3D12_FILL_MODE;
+
+typedef enum D3D12_CULL_MODE
+{
+    D3D12_CULL_MODE_NONE = 1,
+    D3D12_CULL_MODE_FRONT = 2,
+    D3D12_CULL_MODE_BACK = 3,
+} D3D12_CULL_MODE;
+
+typedef enum D3D12_CONSERVATIVE_RASTERIZATION_MODE
+{
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF = 0,
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON = 1,
+} D3D12_CONSERVATIVE_RASTERIZATION_MODE;
+
+typedef struct D3D12_RASTERIZER_DESC
+{
+    D3D12_FILL_MODE FillMode;
+    D3D12_CULL_MODE CullMode;
+    BOOL FrontCounterClockwise;
+    INT DepthBias;
+    FLOAT DepthBiasClamp;
+    FLOAT SlopeScaledDepthBias;
+    BOOL DepthClipEnable;
+    BOOL MultisampleEnable;
+    BOOL AntialiasedLineEnable;
+    UINT ForcedSampleCount;
+    D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;
+} D3D12_RASTERIZER_DESC;
+
+typedef struct D3D12_SO_DECLARATION_ENTRY
+{
+    UINT Stream;
+    const char *SemanticName;
+    UINT SemanticIndex;
+    BYTE StartComponent;
+    BYTE ComponentCount;
+    BYTE OutputSlot;
+} D3D12_SO_DECLARATION_ENTRY;
+
+typedef struct D3D12_STREAM_OUTPUT_DESC
+{
+    const D3D12_SO_DECLARATION_ENTRY *pSODeclaration;
+    UINT NumEntries;
+    const UINT *pBufferStrides;
+    UINT NumStrides;
+    UINT RasterizedStream;
+} D3D12_STREAM_OUTPUT_DESC;
+
+typedef enum D3D12_INPUT_CLASSIFICATION
+{
+    D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA = 0,
+    D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA = 1,
+} D3D12_INPUT_CLASSIFICATION;
+
+typedef struct D3D12_INPUT_ELEMENT_DESC
+{
+    const char *SemanticName;
+    UINT SemanticIndex;
+    DXGI_FORMAT Format;
+    UINT InputSlot;
+    UINT AlignedByteOffset;
+    D3D12_INPUT_CLASSIFICATION InputSlotClass;
+    UINT InstanceDataStepRate;
+} D3D12_INPUT_ELEMENT_DESC;
+
+typedef struct D3D12_INPUT_LAYOUT_DESC
+{
+    const D3D12_INPUT_ELEMENT_DESC *pInputElementDescs;
+    UINT NumElements;
+} D3D12_INPUT_LAYOUT_DESC;
+
+typedef enum D3D12_INDEX_BUFFER_STRIP_CUT_VALUE
+{
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED = 0,
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF = 1,
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF = 2,
+} D3D12_INDEX_BUFFER_STRIP_CUT_VALUE;
+
+typedef D3D_PRIMITIVE_TOPOLOGY D3D12_PRIMITIVE_TOPOLOGY;
+
+typedef enum D3D12_PRIMITIVE_TOPOLOGY_TYPE
+{
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED = 0,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT = 1,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE = 2,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE = 3,
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH = 4,
+} D3D12_PRIMITIVE_TOPOLOGY_TYPE;
+
+typedef struct D3D12_CACHED_PIPELINE_STATE
+{
+    const void *pCachedBlob;
+    SIZE_T CachedBlobSizeInBytes;
+} D3D12_CACHED_PIPELINE_STATE;
+
+typedef enum D3D12_PIPELINE_STATE_FLAGS
+{
+    D3D12_PIPELINE_STATE_FLAG_NONE = 0x0,
+    D3D12_PIPELINE_STATE_FLAG_DEBUG = 0x1,
+} D3D12_PIPELINE_STATE_FLAGS;
+
+typedef struct D3D12_GRAPHICS_PIPELINE_STATE_DESC
+{
+    ID3D12RootSignature *pRootSignature;
+    D3D12_SHADER_BYTECODE VS;
+    D3D12_SHADER_BYTECODE PS;
+    D3D12_SHADER_BYTECODE DS;
+    D3D12_SHADER_BYTECODE HS;
+    D3D12_SHADER_BYTECODE GS;
+    D3D12_STREAM_OUTPUT_DESC StreamOutput;
+    D3D12_BLEND_DESC BlendState;
+    UINT SampleMask;
+    D3D12_RASTERIZER_DESC RasterizerState;
+    D3D12_DEPTH_STENCIL_DESC DepthStencilState;
+    D3D12_INPUT_LAYOUT_DESC InputLayout;
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
+    D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;
+    UINT NumRenderTargets;
+    DXGI_FORMAT RTVFormats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    DXGI_FORMAT DSVFormat;
+    DXGI_SAMPLE_DESC SampleDesc;
+    UINT NodeMask;
+    D3D12_CACHED_PIPELINE_STATE CachedPSO;
+    D3D12_PIPELINE_STATE_FLAGS Flags;
+} D3D12_GRAPHICS_PIPELINE_STATE_DESC;
+
+typedef struct D3D12_COMPUTE_PIPELINE_STATE_DESC
+{
+    ID3D12RootSignature *pRootSignature;
+    D3D12_SHADER_BYTECODE CS;
+    UINT NodeMask;
+    D3D12_CACHED_PIPELINE_STATE CachedPSO;
+    D3D12_PIPELINE_STATE_FLAGS Flags;
+} D3D12_COMPUTE_PIPELINE_STATE_DESC;
+
+typedef enum D3D12_COMMAND_LIST_TYPE
+{
+    D3D12_COMMAND_LIST_TYPE_DIRECT = 0,
+    D3D12_COMMAND_LIST_TYPE_BUNDLE = 1,
+    D3D12_COMMAND_LIST_TYPE_COMPUTE = 2,
+    D3D12_COMMAND_LIST_TYPE_COPY = 3,
+} D3D12_COMMAND_LIST_TYPE;
+
+typedef enum D3D12_COMMAND_QUEUE_PRIORITY
+{
+    D3D12_COMMAND_QUEUE_PRIORITY_NORMAL = 0,
+    D3D12_COMMAND_QUEUE_PRIORITY_HIGH = 100,
+    D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME = 10000,
+} D3D12_COMMAND_QUEUE_PRIORITY;
+
+typedef enum D3D12_COMMAND_QUEUE_FLAGS
+{
+    D3D12_COMMAND_QUEUE_FLAG_NONE = 0x0,
+    D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT = 0x1,
+} D3D12_COMMAND_QUEUE_FLAGS;
+
+typedef struct D3D12_COMMAND_QUEUE_DESC
+{
+    D3D12_COMMAND_LIST_TYPE Type;
+    INT Priority;
+    D3D12_COMMAND_QUEUE_FLAGS Flags;
+    UINT NodeMask;
+} D3D12_COMMAND_QUEUE_DESC;
+
+typedef struct D3D12_FEATURE_DATA_ARCHITECTURE
+{
+    UINT NodeIndex;
+    BOOL TileBasedRenderer;
+    BOOL UMA;
+    BOOL CacheCoherentUMA;
+} D3D12_FEATURE_DATA_ARCHITECTURE;
+
+typedef struct D3D12_FEATURE_DATA_FORMAT_INFO
+{
+    DXGI_FORMAT Format;
+    UINT8 PlaneCount;
+} D3D12_FEATURE_DATA_FORMAT_INFO;
+
+typedef struct D3D12_FEATURE_DATA_FEATURE_LEVELS
+{
+    UINT NumFeatureLevels;
+    const D3D_FEATURE_LEVEL *pFeatureLevelsRequested;
+    D3D_FEATURE_LEVEL MaxSupportedFeatureLevel;
+} D3D12_FEATURE_DATA_FEATURE_LEVELS;
+
+typedef struct D3D12_FEATURE_DATA_ROOT_SIGNATURE
+{
+    D3D_ROOT_SIGNATURE_VERSION HighestVersion;
+} D3D12_FEATURE_DATA_ROOT_SIGNATURE;
+
+typedef struct D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT
+{
+    UINT MaxGPUVirtualAddressBitsPerResource;
+    UINT MaxGPUVirtualAddressBitsPerProcess;
+} D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT;
+
+typedef enum D3D_SHADER_MODEL
+{
+    D3D_SHADER_MODEL_5_1 = 0x51,
+    D3D_SHADER_MODEL_6_0 = 0x60,
+} D3D_SHADER_MODEL;
+
+typedef struct D3D12_FEATURE_DATA_SHADER_MODEL
+{
+    D3D_SHADER_MODEL HighestShaderModel;
+} D3D12_FEATURE_DATA_SHADER_MODEL;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS1
+{
+    BOOL WaveOps;
+    UINT WaveLaneCountMin;
+    UINT WaveLaneCountMax;
+    UINT TotalLaneCount;
+    BOOL ExpandedComputeResourceStates;
+    BOOL Int64ShaderOps;
+}  D3D12_FEATURE_DATA_D3D12_OPTIONS1;
+
+typedef struct D3D12_FEATURE_DATA_ARCHITECTURE1
+{
+    UINT NodeIndex;
+    BOOL TileBasedRenderer;
+    BOOL UMA;
+    BOOL CacheCoherentUMA;
+    BOOL IsolatedMMU;
+}  D3D12_FEATURE_DATA_ARCHITECTURE1;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS2
+{
+    BOOL DepthBoundsTestSupported;
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER ProgrammableSamplePositionsTier;
+}  D3D12_FEATURE_DATA_D3D12_OPTIONS2;
+
+typedef struct D3D12_FEATURE_DATA_SHADER_CACHE
+{
+    D3D12_SHADER_CACHE_SUPPORT_FLAGS SupportFlags;
+}  D3D12_FEATURE_DATA_SHADER_CACHE;
+
+typedef struct D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY
+{
+    D3D12_COMMAND_LIST_TYPE CommandListType;
+    UINT Priority;
+    BOOL PriorityForTypeIsSupported;
+}  D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS3
+{
+    BOOL CopyQueueTimestampQueriesSupported;
+    BOOL CastingFullyTypedFormatSupported;
+    D3D12_COMMAND_LIST_SUPPORT_FLAGS WriteBufferImmediateSupportFlags;
+    D3D12_VIEW_INSTANCING_TIER ViewInstancingTier;
+    BOOL BarycentricsSupported;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS3;
+
+typedef struct D3D12_FEATURE_DATA_EXISTING_HEAPS
+{
+    BOOL Supported;
+}  D3D12_FEATURE_DATA_EXISTING_HEAPS;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS4
+{
+    BOOL MSAA64KBAlignedTextureSupported;
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER SharedResourceCompatibilityTier;
+    BOOL Native16BitShaderOpsSupported;
+}  D3D12_FEATURE_DATA_D3D12_OPTIONS4;
+
+typedef struct D3D12_FEATURE_DATA_SERIALIZATION
+{
+    UINT NodeIndex;
+    D3D12_HEAP_SERIALIZATION_TIER HeapSerializationTier;
+}  D3D12_FEATURE_DATA_SERIALIZATION;
+
+typedef struct D3D12_FEATURE_DATA_CROSS_NODE
+{
+    D3D12_CROSS_NODE_SHARING_TIER SharingTier;
+    BOOL AtomicShaderInstructions;
+}  D3D12_FEATURE_DATA_CROSS_NODE;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS5
+{
+    BOOL SRVOnlyTiledResourceTier3;
+    D3D12_RENDER_PASS_TIER RenderPassesTier;
+    D3D12_RAYTRACING_TIER RaytracingTier;
+} D3D12_FEATURE_DATA_D3D12_OPTIONS5;
+
+typedef enum D3D12_FEATURE
+{
+    D3D12_FEATURE_D3D12_OPTIONS = 0,
+    D3D12_FEATURE_ARCHITECTURE = 1,
+    D3D12_FEATURE_FEATURE_LEVELS = 2,
+    D3D12_FEATURE_FORMAT_SUPPORT = 3,
+    D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS = 4,
+    D3D12_FEATURE_FORMAT_INFO = 5,
+    D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT = 6,
+    D3D12_FEATURE_SHADER_MODEL = 7,
+    D3D12_FEATURE_D3D12_OPTIONS1 = 8,
+    D3D12_FEATURE_ROOT_SIGNATURE = 12,
+    D3D12_FEATURE_ARCHITECTURE1 = 16,
+    D3D12_FEATURE_D3D12_OPTIONS2 = 18,
+    D3D12_FEATURE_SHADER_CACHE = 19,
+    D3D12_FEATURE_COMMAND_QUEUE_PRIORITY = 20,
+    D3D12_FEATURE_D3D12_OPTIONS3 = 21,
+    D3D12_FEATURE_EXISTING_HEAPS = 22,
+    D3D12_FEATURE_D3D12_OPTIONS4 = 23,
+    D3D12_FEATURE_SERIALIZATION = 24,
+    D3D12_FEATURE_CROSS_NODE = 25,
+    D3D12_FEATURE_D3D12_OPTIONS5 = 27,
+} D3D12_FEATURE;
+
+typedef struct D3D12_MEMCPY_DEST
+{
+    void *pData;
+    SIZE_T RowPitch;
+    SIZE_T SlicePitch;
+} D3D12_MEMCPY_DEST;
+
+typedef struct D3D12_SUBRESOURCE_DATA
+{
+    const void *pData;
+    LONG_PTR RowPitch;
+    LONG_PTR SlicePitch;
+} D3D12_SUBRESOURCE_DATA;
+
+typedef enum D3D12_MULTIPLE_FENCE_WAIT_FLAGS
+{
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_NONE = 0x0,
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY = 0x1,
+    D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL = 0x0,
+} D3D12_MULTIPLE_FENCE_WAIT_FLAGS;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_MULTIPLE_FENCE_WAIT_FLAGS);")
+
+typedef enum D3D12_RESIDENCY_PRIORITY
+{
+    D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000,
+    D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000,
+    D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000,
+    D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000,
+    D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000,
+} D3D12_RESIDENCY_PRIORITY;
+
+typedef struct D3D12_WRITEBUFFERIMMEDIATE_PARAMETER
+{
+    D3D12_GPU_VIRTUAL_ADDRESS Dest;
+    UINT32 Value;
+} D3D12_WRITEBUFFERIMMEDIATE_PARAMETER;
+
+[
+    uuid(c4fec28f-7966-4e95-9f94-f431cb56c3b8),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Object : IUnknown
+{
+    HRESULT GetPrivateData(REFGUID guid, UINT *data_size, void *data);
+    HRESULT SetPrivateData(REFGUID guid, UINT data_size, const void *data);
+    HRESULT SetPrivateDataInterface(REFGUID guid, const IUnknown *data);
+    HRESULT SetName(const WCHAR *name);
+}
+
+[
+    uuid(905db94b-a00c-4140-9df5-2b64ca9ea357),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12DeviceChild : ID3D12Object
+{
+    HRESULT GetDevice(REFIID riid, void **device);
+}
+
+[
+    uuid(63ee58fb-1268-4835-86da-f008ce62f0d6),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Pageable : ID3D12DeviceChild
+{
+}
+
+[
+    uuid(6b3b2502-6e51-45b3-90ee-9884265e8df3),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Heap : ID3D12Pageable
+{
+    D3D12_HEAP_DESC GetDesc();
+}
+
+[
+    uuid(696442be-a72e-4059-bc79-5b5c98040fad),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Resource : ID3D12Pageable
+{
+    HRESULT Map(UINT sub_resource, const D3D12_RANGE *read_range, void **data);
+    void Unmap(UINT sub_resource, const D3D12_RANGE *written_range);
+
+    D3D12_RESOURCE_DESC GetDesc();
+
+    D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress();
+
+    HRESULT WriteToSubresource(UINT dst_sub_resource, const D3D12_BOX *dst_box,
+            const void *src_data, UINT src_row_pitch, UINT src_slice_pitch);
+    HRESULT ReadFromSubresource(void *dst_data, UINT dst_row_pitch, UINT dst_slice_pitch,
+            UINT src_sub_resource, const D3D12_BOX *src_box);
+
+    HRESULT GetHeapProperties(D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS *flags);
+}
+
+[
+    uuid(7116d91c-e7e4-47ce-b8c6-ec8168f437e5),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12CommandList : ID3D12DeviceChild
+{
+    D3D12_COMMAND_LIST_TYPE GetType();
+}
+
+typedef enum D3D12_TILE_COPY_FLAGS
+{
+    D3D12_TILE_COPY_FLAG_NONE = 0x0,
+    D3D12_TILE_COPY_FLAG_NO_HAZARD = 0x1,
+    D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE = 0x2,
+    D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER = 0x4,
+} D3D12_TILE_COPY_FLAGS;
+
+typedef struct D3D12_INDEX_BUFFER_VIEW
+{
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+    DXGI_FORMAT Format;
+} D3D12_INDEX_BUFFER_VIEW;
+
+typedef struct D3D12_VERTEX_BUFFER_VIEW
+{
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT SizeInBytes;
+    UINT StrideInBytes;
+} D3D12_VERTEX_BUFFER_VIEW;
+
+typedef struct D3D12_STREAM_OUTPUT_BUFFER_VIEW
+{
+    D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
+    UINT64 SizeInBytes;
+    D3D12_GPU_VIRTUAL_ADDRESS BufferFilledSizeLocation;
+} D3D12_STREAM_OUTPUT_BUFFER_VIEW;
+
+typedef enum D3D12_CLEAR_FLAGS
+{
+    D3D12_CLEAR_FLAG_DEPTH = 0x1,
+    D3D12_CLEAR_FLAG_STENCIL = 0x2,
+} D3D12_CLEAR_FLAGS;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_CLEAR_FLAGS);")
+
+typedef struct D3D12_DISCARD_REGION
+{
+    UINT NumRects;
+    const D3D12_RECT *pRects;
+    UINT FirstSubresource;
+    UINT NumSubresources;
+} D3D12_DISCARD_REGION;
+
+typedef enum D3D12_QUERY_TYPE
+{
+    D3D12_QUERY_TYPE_OCCLUSION = 0,
+    D3D12_QUERY_TYPE_BINARY_OCCLUSION = 1,
+    D3D12_QUERY_TYPE_TIMESTAMP = 2,
+    D3D12_QUERY_TYPE_PIPELINE_STATISTICS = 3,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 = 4,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM1 = 5,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM2 = 6,
+    D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3 = 7,
+} D3D12_QUERY_TYPE;
+
+typedef struct D3D12_QUERY_DATA_PIPELINE_STATISTICS
+{
+    UINT64 IAVertices;
+    UINT64 IAPrimitives;
+    UINT64 VSInvocations;
+    UINT64 GSInvocations;
+    UINT64 GSPrimitives;
+    UINT64 CInvocations;
+    UINT64 CPrimitives;
+    UINT64 PSInvocations;
+    UINT64 HSInvocations;
+    UINT64 DSInvocations;
+    UINT64 CSInvocations;
+} D3D12_QUERY_DATA_PIPELINE_STATISTICS;
+
+typedef struct D3D12_QUERY_DATA_SO_STATISTICS
+{
+    UINT64 NumPrimitivesWritten;
+    UINT64 PrimitivesStorageNeeded;
+} D3D12_QUERY_DATA_SO_STATISTICS;
+
+typedef enum D3D12_PREDICATION_OP
+{
+    D3D12_PREDICATION_OP_EQUAL_ZERO = 0,
+    D3D12_PREDICATION_OP_NOT_EQUAL_ZERO = 1,
+} D3D12_PREDICATION_OP;
+
+[
+    uuid(8efb471d-616c-4f49-90f7-127bb763fa51),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12DescriptorHeap : ID3D12Pageable
+{
+    D3D12_DESCRIPTOR_HEAP_DESC GetDesc();
+
+    D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandleForHeapStart();
+    D3D12_GPU_DESCRIPTOR_HANDLE GetGPUDescriptorHandleForHeapStart();
+}
+
+[
+    uuid(0d9658ae-ed45-469e-a61d-970ec583cab4),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12QueryHeap : ID3D12Pageable
+{
+}
+
+[
+    uuid(c36a797c-ec80-4f0a-8985-a7b2475082d1),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12CommandSignature : ID3D12Pageable
+{
+}
+
+[
+    uuid(5b160d0f-ac1b-4185-8ba8-b3ae42a5a455),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12GraphicsCommandList : ID3D12CommandList
+{
+    HRESULT Close();
+
+    HRESULT Reset(ID3D12CommandAllocator *allocator, ID3D12PipelineState *initial_state);
+
+    HRESULT ClearState(ID3D12PipelineState *pipeline_state);
+
+    void DrawInstanced(UINT vertex_count_per_instance, UINT instance_count,
+            UINT start_vertex_location, UINT start_instance_location);
+    void DrawIndexedInstanced(UINT index_count_per_instance, UINT instance_count,
+            UINT start_vertex_location, INT base_vertex_location, UINT start_instance_location);
+
+    void Dispatch(UINT x, UINT u, UINT z);
+
+    void CopyBufferRegion(ID3D12Resource *dst_buffer, UINT64 dst_offset,
+            ID3D12Resource *src_buffer, UINT64 src_offset, UINT64 byte_count);
+    void CopyTextureRegion(const D3D12_TEXTURE_COPY_LOCATION *dst,
+            UINT dst_x, UINT dst_y, UINT dst_z,
+            const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box);
+    void CopyResource(ID3D12Resource *dst_resource, ID3D12Resource *src_resource);
+
+    void CopyTiles(ID3D12Resource *tiled_resource,
+            const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+            const D3D12_TILE_REGION_SIZE *tile_region_size,
+            ID3D12Resource *buffer,
+            UINT64 buffer_offset,
+            D3D12_TILE_COPY_FLAGS flags);
+
+    void ResolveSubresource(ID3D12Resource *dst_resource, UINT dst_sub_resource,
+            ID3D12Resource *src_resource, UINT src_sub_resource,
+            DXGI_FORMAT format);
+
+    void IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY primitive_topology);
+
+    void RSSetViewports(UINT viewport_count, const D3D12_VIEWPORT *viewports);
+    void RSSetScissorRects(UINT rect_count, const D3D12_RECT *rects);
+
+    void OMSetBlendFactor(const FLOAT blend_factor[4]);
+    void OMSetStencilRef(UINT stencil_ref);
+
+    void SetPipelineState(ID3D12PipelineState *pipeline_state);
+
+    void ResourceBarrier(UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers);
+
+    void ExecuteBundle(ID3D12GraphicsCommandList *command_list);
+
+    void SetDescriptorHeaps(UINT heap_count, ID3D12DescriptorHeap * const *heaps);
+
+    void SetComputeRootSignature(ID3D12RootSignature *root_signature);
+    void SetGraphicsRootSignature(ID3D12RootSignature *root_signature);
+
+    void SetComputeRootDescriptorTable(UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+    void SetGraphicsRootDescriptorTable(UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
+
+    void SetComputeRoot32BitConstant(UINT root_parameter_index, UINT data, UINT dst_offset);
+    void SetGraphicsRoot32BitConstant(UINT root_parameter_index, UINT data, UINT dst_offset);
+
+    void SetComputeRoot32BitConstants(UINT root_parameter_index, UINT constant_count, const void *data,
+            UINT dst_offset);
+    void SetGraphicsRoot32BitConstants(UINT root_parameter_index, UINT constant_count, const void *data,
+            UINT dst_offset);
+
+    void SetComputeRootConstantBufferView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+    void SetGraphicsRootConstantBufferView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void SetComputeRootShaderResourceView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+    void SetGraphicsRootShaderResourceView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void SetComputeRootUnorderedAccessView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+    void SetGraphicsRootUnorderedAccessView(UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
+
+    void IASetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW *view);
+    void IASetVertexBuffers(UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views);
+
+    void SOSetTargets(UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views);
+
+    void OMSetRenderTargets(UINT render_target_descriptor_count,
+            const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+            BOOL single_descriptor_handle,
+            const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
+
+    void ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags,
+            FLOAT depth, UINT8 stencil, UINT rect_count, const D3D12_RECT *rects);
+    void ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4],
+            UINT rect_count, const D3D12_RECT *rects);
+    void ClearUnorderedAccessViewUint(D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+            D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const UINT values[4],
+            UINT rect_count, const D3D12_RECT *rects);
+    void ClearUnorderedAccessViewFloat(D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle,
+            D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const float values[4],
+            UINT rect_count, const D3D12_RECT *rects);
+
+    void DiscardResource(ID3D12Resource *resource, const D3D12_DISCARD_REGION *region);
+
+    void BeginQuery(ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
+    void EndQuery(ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
+    void ResolveQueryData(ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type,
+            UINT start_index, UINT query_count,
+            ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset);
+
+    void SetPredication(ID3D12Resource *buffer, UINT64 aligned_buffer_offset,
+            D3D12_PREDICATION_OP operation);
+
+    void SetMarker(UINT metadata, const void *data, UINT size);
+    void BeginEvent(UINT metadata, const void *data, UINT size);
+    void EndEvent();
+
+    void ExecuteIndirect(ID3D12CommandSignature *command_signature,
+            UINT max_command_count, ID3D12Resource *arg_buffer, UINT64 arg_buffer_offset,
+            ID3D12Resource *count_buffer, UINT64 count_buffer_offset);
+}
+
+[
+    uuid(553103fb-1fe7-4557-bb38-946d7d0e7ca7),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12GraphicsCommandList1 : ID3D12GraphicsCommandList
+{
+    void AtomicCopyBufferUINT(ID3D12Resource *dst_buffer, UINT64 dst_offset,
+            ID3D12Resource *src_buffer, UINT64 src_offset,
+            UINT dependent_resource_count, ID3D12Resource * const *dependent_resources,
+            const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void AtomicCopyBufferUINT64(ID3D12Resource *dst_buffer, UINT64 dst_offset,
+            ID3D12Resource *src_buffer, UINT64 src_offset,
+            UINT dependent_resource_count, ID3D12Resource * const *dependent_resources,
+            const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges);
+
+    void OMSetDepthBounds(FLOAT min, FLOAT max);
+
+    void SetSamplePositions(UINT sample_count, UINT pixel_count,
+            D3D12_SAMPLE_POSITION *sample_positions);
+
+    void ResolveSubresourceRegion(ID3D12Resource *dst_resource,
+            UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y,
+            ID3D12Resource *src_resource, UINT src_sub_resource_idx,
+            D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode);
+
+    void SetViewInstanceMask(UINT mask);
+}
+
+[
+    uuid(38c3e585-ff17-412c-9150-4fc6f9d72a28),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12GraphicsCommandList2 : ID3D12GraphicsCommandList1
+{
+    void WriteBufferImmediate(UINT count,
+            const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters,
+            const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes);
+}
+
+typedef enum D3D12_TILE_RANGE_FLAGS
+{
+    D3D12_TILE_RANGE_FLAG_NONE = 0x0,
+    D3D12_TILE_RANGE_FLAG_NULL = 0x1,
+    D3D12_TILE_RANGE_FLAG_SKIP = 0x2,
+    D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE = 0x4
+} D3D12_TILE_RANGE_FLAGS;
+
+typedef enum D3D12_TILE_MAPPING_FLAGS
+{
+    D3D12_TILE_MAPPING_FLAG_NONE = 0x0,
+    D3D12_TILE_MAPPING_FLAG_NO_HAZARD = 0x1,
+} D3D12_TILE_MAPPING_FLAGS;
+
+[
+    uuid(0ec870a6-5d7e-4c22-8cfc-5baae07616ed),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12CommandQueue : ID3D12Pageable
+{
+    void UpdateTileMappings(ID3D12Resource *resource, UINT region_count,
+            const D3D12_TILED_RESOURCE_COORDINATE *region_start_coordinates,
+            const D3D12_TILE_REGION_SIZE *region_sizes,
+            UINT range_count,
+            const D3D12_TILE_RANGE_FLAGS *range_flags,
+            UINT *heap_range_offsets,
+            UINT *range_tile_counts,
+            D3D12_TILE_MAPPING_FLAGS flags);
+
+    void CopyTileMappings(ID3D12Resource *dst_resource,
+            const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate,
+            ID3D12Resource *src_resource,
+            const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate,
+            const D3D12_TILE_REGION_SIZE *region_size,
+            D3D12_TILE_MAPPING_FLAGS flags);
+
+    void ExecuteCommandLists(UINT command_list_count,
+            ID3D12CommandList * const * command_lists);
+
+    void SetMarker(UINT metadata, const void *data, UINT size);
+    void BeginEvent(UINT metadata, const void *data, UINT size);
+    void EndEvent();
+
+    HRESULT Signal(ID3D12Fence *fence, UINT64 value);
+    HRESULT Wait(ID3D12Fence *fence, UINT64 value);
+
+    HRESULT GetTimestampFrequency(UINT64 *frequency);
+    HRESULT GetClockCalibration(UINT64 *gpu_timestamp, UINT64 *cpu_timestamp);
+
+    D3D12_COMMAND_QUEUE_DESC GetDesc();
+}
+
+typedef enum D3D12_FENCE_FLAGS
+{
+    D3D12_FENCE_FLAG_NONE = 0x0,
+    D3D12_FENCE_FLAG_SHARED = 0x1,
+    D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER = 0x2,
+} D3D12_FENCE_FLAGS;
+
+typedef enum D3D12_QUERY_HEAP_TYPE
+{
+    D3D12_QUERY_HEAP_TYPE_OCCLUSION = 0,
+    D3D12_QUERY_HEAP_TYPE_TIMESTAMP = 1,
+    D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS = 2,
+    D3D12_QUERY_HEAP_TYPE_SO_STATISTICS = 3,
+} D3D12_QUERY_HEAP_TYPE;
+
+typedef struct D3D12_QUERY_HEAP_DESC
+{
+    D3D12_QUERY_HEAP_TYPE Type;
+    UINT Count;
+    UINT NodeMask;
+} D3D12_QUERY_HEAP_DESC;
+
+typedef enum D3D12_INDIRECT_ARGUMENT_TYPE
+{
+    D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
+    D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
+    D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
+    D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW,
+    D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW,
+    D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
+    D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW,
+    D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW,
+    D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW,
+} D3D12_INDIRECT_ARGUMENT_TYPE;
+
+typedef struct D3D12_INDIRECT_ARGUMENT_DESC
+{
+    D3D12_INDIRECT_ARGUMENT_TYPE Type;
+    union
+    {
+        struct
+        {
+            UINT Slot;
+        } VertexBuffer;
+        struct
+        {
+            UINT RootParameterIndex;
+            UINT DestOffsetIn32BitValues;
+            UINT Num32BitValuesToSet;
+        } Constant;
+        struct
+        {
+            UINT RootParameterIndex;
+        } ConstantBufferView;
+        struct
+        {
+            UINT RootParameterIndex;
+        } ShaderResourceView;
+        struct
+        {
+            UINT RootParameterIndex;
+        } UnorderedAccessView;
+    };
+} D3D12_INDIRECT_ARGUMENT_DESC;
+
+typedef struct D3D12_COMMAND_SIGNATURE_DESC
+{
+    UINT ByteStride;
+    UINT NumArgumentDescs;
+    const D3D12_INDIRECT_ARGUMENT_DESC *pArgumentDescs;
+    UINT NodeMask;
+} D3D12_COMMAND_SIGNATURE_DESC;
+
+[
+    uuid(c54a6b66-72df-4ee8-8be5-a946a1429214),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12RootSignature : ID3D12DeviceChild
+{
+}
+
+[
+    uuid(765a30f3-f624-4c6f-a828-ace948622445),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12PipelineState : ID3D12Pageable
+{
+    HRESULT GetCachedBlob(ID3DBlob **blob);
+}
+
+[
+    uuid(0a753dcf-c4d8-4b91-adf6-be5a60d95a76),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Fence : ID3D12Pageable
+{
+    UINT64 GetCompletedValue();
+    HRESULT SetEventOnCompletion(UINT64 value, HANDLE event);
+    HRESULT Signal(UINT64 value);
+}
+
+[
+    uuid(6102dee4-af59-4b09-b999-b44d73f09b24),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12CommandAllocator : ID3D12Pageable
+{
+    HRESULT Reset();
+}
+
+[
+    uuid(189819f1-1db6-4b57-be54-1821339b85f7),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Device : ID3D12Object
+{
+    UINT GetNodeCount();
+
+    HRESULT CreateCommandQueue(const D3D12_COMMAND_QUEUE_DESC *desc,
+            REFIID riid, void **command_queue);
+    HRESULT CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type,
+            REFIID riid, void **command_allocator);
+    HRESULT CreateGraphicsPipelineState(const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc,
+            REFIID riid, void **pipeline_state);
+    HRESULT CreateComputePipelineState(const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc,
+            REFIID riid, void **pipeline_state);
+    HRESULT CreateCommandList(UINT node_mask,
+            D3D12_COMMAND_LIST_TYPE type,
+            ID3D12CommandAllocator *command_allocator,
+            ID3D12PipelineState *initial_pipeline_state,
+            REFIID riid, void **command_list);
+
+    HRESULT CheckFeatureSupport(D3D12_FEATURE feature,
+            void *feature_data, UINT feature_data_size);
+
+    HRESULT CreateDescriptorHeap(const D3D12_DESCRIPTOR_HEAP_DESC *desc,
+            REFIID riid, void **descriptor_heap);
+    UINT GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    HRESULT CreateRootSignature(UINT node_mask,
+            const void *bytecode, SIZE_T bytecode_length,
+            REFIID riid, void **root_signature);
+
+    void CreateConstantBufferView(const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+    void CreateShaderResourceView(ID3D12Resource *resource,
+            const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+    void CreateUnorderedAccessView(ID3D12Resource *resource, ID3D12Resource *counter_resource,
+            const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+    void CreateRenderTargetView(ID3D12Resource *resource,
+            const D3D12_RENDER_TARGET_VIEW_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+    void CreateDepthStencilView(ID3D12Resource *resource,
+            const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+    void CreateSampler(const D3D12_SAMPLER_DESC *desc,
+            D3D12_CPU_DESCRIPTOR_HANDLE descriptor);
+
+    void CopyDescriptors(UINT dst_descriptor_range_count,
+            const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
+            const UINT *dst_descriptor_range_sizes,
+            UINT src_descriptor_range_count,
+            const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
+            const UINT *src_descriptor_range_sizes,
+            D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+    void CopyDescriptorsSimple(UINT descriptor_count,
+            const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
+            const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
+            D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type);
+
+    D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(UINT visible_mask,
+            UINT reource_desc_count, const D3D12_RESOURCE_DESC *resource_descs);
+
+    D3D12_HEAP_PROPERTIES GetCustomHeapProperties(UINT node_mask,
+            D3D12_HEAP_TYPE heap_type);
+
+    HRESULT CreateCommittedResource(const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+            const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+            const D3D12_CLEAR_VALUE *optimized_clear_value,
+            REFIID riid, void **resource);
+
+    HRESULT CreateHeap(const D3D12_HEAP_DESC *desc, REFIID riid, void **heap);
+
+    HRESULT CreatePlacedResource(ID3D12Heap *heap, UINT64 heap_offset,
+            const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+            const D3D12_CLEAR_VALUE *optimized_clear_value,
+            REFIID riid, void **resource);
+    HRESULT CreateReservedResource(const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+            const D3D12_CLEAR_VALUE *optimized_clear_value,
+            REFIID riid, void **resource);
+
+    HRESULT CreateSharedHandle(ID3D12DeviceChild *object,
+            const SECURITY_ATTRIBUTES *attributes, DWORD access,
+            const WCHAR *name, HANDLE *handle);
+    HRESULT OpenSharedHandle(HANDLE handle,
+            REFIID riid, void **object);
+    HRESULT OpenSharedHandleByName(const WCHAR *name, DWORD access, HANDLE *handle);
+
+    HRESULT MakeResident(UINT object_count, ID3D12Pageable * const *objects);
+    HRESULT Evict(UINT object_count, ID3D12Pageable * const *objects);
+
+    HRESULT CreateFence(UINT64 initial_value, D3D12_FENCE_FLAGS flags, REFIID riid, void **fence);
+
+    HRESULT GetDeviceRemovedReason();
+
+    void GetCopyableFootprints(const D3D12_RESOURCE_DESC *desc,
+            UINT first_sub_resource,
+            UINT sub_resource_count,
+            UINT64 base_offset,
+            D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
+            UINT *row_count,
+            UINT64 *row_size,
+            UINT64 *total_bytes);
+
+    HRESULT CreateQueryHeap(const D3D12_QUERY_HEAP_DESC *desc,
+            REFIID riid, void **heap);
+
+    HRESULT SetStablePowerState(BOOL enable);
+
+    HRESULT CreateCommandSignature(const D3D12_COMMAND_SIGNATURE_DESC *desc,
+            ID3D12RootSignature *root_signature,
+            REFIID riid, void **command_signature);
+
+    void GetResourceTiling(ID3D12Resource *resource,
+            UINT *total_tile_count,
+            D3D12_PACKED_MIP_INFO *packed_mip_info,
+            D3D12_TILE_SHAPE *standard_tile_shape,
+            UINT *sub_resource_tiling_count,
+            UINT first_sub_resource_tiling,
+            D3D12_SUBRESOURCE_TILING *sub_resource_tilings);
+
+    LUID GetAdapterLuid();
+}
+
+[
+    uuid(77acce80-638e-4e65-8895-c1f23386863e),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Device1 : ID3D12Device
+{
+    HRESULT CreatePipelineLibrary(const void *blob, SIZE_T blob_size, REFIID iid, void **lib);
+
+    HRESULT SetEventOnMultipleFenceCompletion(ID3D12Fence * const *fences,
+            const UINT64 *values, UINT fence_count, D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags, HANDLE event);
+
+    HRESULT SetResidencyPriority(UINT object_count, ID3D12Pageable * const *objects,
+            const D3D12_RESIDENCY_PRIORITY *priorities);
+}
+
+[
+    uuid(34ab647b-3cc8-46ac-841b-c0965645c046),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12RootSignatureDeserializer : IUnknown
+{
+    const D3D12_ROOT_SIGNATURE_DESC *GetRootSignatureDesc();
+}
+
+[
+    uuid(7f91ce67-090c-4bb7-b78e-ed8ff2e31da0),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12VersionedRootSignatureDeserializer : IUnknown
+{
+    HRESULT GetRootSignatureDescAtVersion(D3D_ROOT_SIGNATURE_VERSION version,
+            const D3D12_VERSIONED_ROOT_SIGNATURE_DESC **desc);
+
+    const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *GetUnconvertedRootSignatureDesc();
+};
+
+[local] HRESULT __stdcall D3D12CreateRootSignatureDeserializer(
+        const void *data, SIZE_T data_size, REFIID iid, void **deserializer);
+
+typedef HRESULT (__stdcall *PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER)(
+        const void *data, SIZE_T data_size, REFIID iid, void **deserializer);
+
+[local] HRESULT __stdcall D3D12CreateVersionedRootSignatureDeserializer(
+        const void *data, SIZE_T data_size, REFIID iid, void **deserializer);
+
+[local] HRESULT __stdcall D3D12SerializeRootSignature(
+        const D3D12_ROOT_SIGNATURE_DESC *root_signature_desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
+
+typedef HRESULT (__stdcall *PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)(
+        const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc, ID3DBlob **blob, ID3DBlob **error_blob);
+
+[local] HRESULT __stdcall D3D12SerializeVersionedRootSignature(
+        const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *root_signature_desc,
+        ID3DBlob **blob, ID3DBlob **error_blob);
+
+typedef HRESULT (__stdcall *PFN_D3D12_CREATE_DEVICE)(IUnknown *adapter,
+        D3D_FEATURE_LEVEL minimum_feature_level, REFIID iid, void **device);
+
+[local] HRESULT __stdcall D3D12CreateDevice(IUnknown *adapter,
+        D3D_FEATURE_LEVEL minimum_feature_level, REFIID iid, void **device);
+
+typedef HRESULT (__stdcall *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID iid, void **debug);
+
+[local] HRESULT __stdcall D3D12GetDebugInterface(REFIID iid, void **debug);
diff --git a/dlls/vkd3d/include/vkd3d_d3d12sdklayers.h b/dlls/vkd3d/include/vkd3d_d3d12sdklayers.h
new file mode 100644
index 00000000000..59bd50ff155
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3d12sdklayers.h
@@ -0,0 +1,228 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_d3d12sdklayers.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_d3d12sdklayers_h__
+#define __vkd3d_d3d12sdklayers_h__
+
+/* Forward declarations */
+
+#ifndef __ID3D12Debug_FWD_DEFINED__
+#define __ID3D12Debug_FWD_DEFINED__
+typedef interface ID3D12Debug ID3D12Debug;
+#ifdef __cplusplus
+interface ID3D12Debug;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D12Debug1_FWD_DEFINED__
+#define __ID3D12Debug1_FWD_DEFINED__
+typedef interface ID3D12Debug1 ID3D12Debug1;
+#ifdef __cplusplus
+interface ID3D12Debug1;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_d3d12.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ * ID3D12Debug interface
+ */
+#ifndef __ID3D12Debug_INTERFACE_DEFINED__
+#define __ID3D12Debug_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Debug, 0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("344488b7-6846-474b-b989-f027448245e0")
+ID3D12Debug : public IUnknown
+{
+    virtual void STDMETHODCALLTYPE EnableDebugLayer(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Debug, 0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0)
+#endif
+#else
+typedef struct ID3D12DebugVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Debug *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Debug *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Debug *This);
+
+    /*** ID3D12Debug methods ***/
+    void (STDMETHODCALLTYPE *EnableDebugLayer)(
+        ID3D12Debug *This);
+
+    END_INTERFACE
+} ID3D12DebugVtbl;
+
+interface ID3D12Debug {
+    CONST_VTBL ID3D12DebugVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Debug_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Debug_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Debug_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Debug methods ***/
+#define ID3D12Debug_EnableDebugLayer(This) (This)->lpVtbl->EnableDebugLayer(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Debug_QueryInterface(ID3D12Debug* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Debug_AddRef(ID3D12Debug* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Debug_Release(ID3D12Debug* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Debug methods ***/
+static FORCEINLINE void ID3D12Debug_EnableDebugLayer(ID3D12Debug* This) {
+    This->lpVtbl->EnableDebugLayer(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Debug_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * ID3D12Debug1 interface
+ */
+#ifndef __ID3D12Debug1_INTERFACE_DEFINED__
+#define __ID3D12Debug1_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D12Debug1, 0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("affaa4ca-63fe-4d8e-b8ad-159000af4304")
+ID3D12Debug1 : public IUnknown
+{
+    virtual void STDMETHODCALLTYPE EnableDebugLayer(
+        ) = 0;
+
+    virtual void STDMETHODCALLTYPE SetEnableGPUBasedValidation(
+        BOOL enable) = 0;
+
+    virtual void STDMETHODCALLTYPE SetEnableSynchronizedCommandQueueValidation(
+        BOOL enable) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D12Debug1, 0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04)
+#endif
+#else
+typedef struct ID3D12Debug1Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D12Debug1 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D12Debug1 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D12Debug1 *This);
+
+    /*** ID3D12Debug1 methods ***/
+    void (STDMETHODCALLTYPE *EnableDebugLayer)(
+        ID3D12Debug1 *This);
+
+    void (STDMETHODCALLTYPE *SetEnableGPUBasedValidation)(
+        ID3D12Debug1 *This,
+        BOOL enable);
+
+    void (STDMETHODCALLTYPE *SetEnableSynchronizedCommandQueueValidation)(
+        ID3D12Debug1 *This,
+        BOOL enable);
+
+    END_INTERFACE
+} ID3D12Debug1Vtbl;
+
+interface ID3D12Debug1 {
+    CONST_VTBL ID3D12Debug1Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D12Debug1_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D12Debug1_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D12Debug1_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D12Debug1 methods ***/
+#define ID3D12Debug1_EnableDebugLayer(This) (This)->lpVtbl->EnableDebugLayer(This)
+#define ID3D12Debug1_SetEnableGPUBasedValidation(This,enable) (This)->lpVtbl->SetEnableGPUBasedValidation(This,enable)
+#define ID3D12Debug1_SetEnableSynchronizedCommandQueueValidation(This,enable) (This)->lpVtbl->SetEnableSynchronizedCommandQueueValidation(This,enable)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D12Debug1_QueryInterface(ID3D12Debug1* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D12Debug1_AddRef(ID3D12Debug1* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D12Debug1_Release(ID3D12Debug1* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D12Debug1 methods ***/
+static FORCEINLINE void ID3D12Debug1_EnableDebugLayer(ID3D12Debug1* This) {
+    This->lpVtbl->EnableDebugLayer(This);
+}
+static FORCEINLINE void ID3D12Debug1_SetEnableGPUBasedValidation(ID3D12Debug1* This,BOOL enable) {
+    This->lpVtbl->SetEnableGPUBasedValidation(This,enable);
+}
+static FORCEINLINE void ID3D12Debug1_SetEnableSynchronizedCommandQueueValidation(ID3D12Debug1* This,BOOL enable) {
+    This->lpVtbl->SetEnableSynchronizedCommandQueueValidation(This,enable);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D12Debug1_INTERFACE_DEFINED__ */
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_d3d12sdklayers_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_d3d12sdklayers.idl b/dlls/vkd3d/include/vkd3d_d3d12sdklayers.idl
new file mode 100644
index 00000000000..76634628a67
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3d12sdklayers.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-2019 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_d3d12.idl";
+
+[
+    uuid(344488b7-6846-474b-b989-f027448245e0),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Debug : IUnknown
+{
+    void EnableDebugLayer();
+}
+
+[
+    uuid(affaa4ca-63fe-4d8e-b8ad-159000af4304),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D12Debug1 : IUnknown
+{
+    void EnableDebugLayer();
+    void SetEnableGPUBasedValidation(BOOL enable);
+    void SetEnableSynchronizedCommandQueueValidation(BOOL enable);
+}
diff --git a/dlls/vkd3d/include/vkd3d_d3dcommon.h b/dlls/vkd3d/include/vkd3d_d3dcommon.h
new file mode 100644
index 00000000000..7c9e7206794
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3dcommon.h
@@ -0,0 +1,296 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_d3dcommon.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_d3dcommon_h__
+#define __vkd3d_d3dcommon_h__
+
+/* Forward declarations */
+
+#ifndef __IUnknown_FWD_DEFINED__
+#define __IUnknown_FWD_DEFINED__
+typedef interface IUnknown IUnknown;
+#ifdef __cplusplus
+interface IUnknown;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __ID3D10Blob_FWD_DEFINED__
+#define __ID3D10Blob_FWD_DEFINED__
+typedef interface ID3D10Blob ID3D10Blob;
+#ifdef __cplusplus
+interface ID3D10Blob;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __VKD3D_UNKNOWN_H
+#define __VKD3D_UNKNOWN_H
+#if 0
+typedef IID *REFIID;
+typedef IID *REFGUID;
+#endif
+#if !defined(_WIN32)
+typedef void *HWND;
+typedef void *HMODULE;
+typedef struct LUID {
+    DWORD LowPart;
+    LONG HighPart;
+} LUID;
+typedef struct _RECT {
+    LONG left;
+    LONG top;
+    LONG right;
+    LONG bottom;
+} RECT;
+#endif
+/*****************************************************************************
+ * IUnknown interface
+ */
+#ifndef __IUnknown_INTERFACE_DEFINED__
+#define __IUnknown_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("00000000-0000-0000-c000-000000000046")
+IUnknown
+{
+
+    BEGIN_INTERFACE
+
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+        REFIID riid,
+        void **object) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE AddRef(
+        ) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE Release(
+        ) = 0;
+
+    END_INTERFACE
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46)
+#endif
+#else
+typedef struct IUnknownVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IUnknown *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IUnknown *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IUnknown *This);
+
+    END_INTERFACE
+} IUnknownVtbl;
+
+interface IUnknown {
+    CONST_VTBL IUnknownVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IUnknown_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IUnknown_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IUnknown_Release(This) (This)->lpVtbl->Release(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IUnknown_QueryInterface(IUnknown* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IUnknown_AddRef(IUnknown* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IUnknown_Release(IUnknown* This) {
+    return This->lpVtbl->Release(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IUnknown_INTERFACE_DEFINED__ */
+
+#endif   /* __VKD3D_UNKNOWN_H */
+typedef enum D3D_PRIMITIVE_TOPOLOGY {
+    D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
+    D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
+    D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
+    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
+    D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
+    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
+    D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
+    D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34,
+    D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = 35,
+    D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = 36,
+    D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = 37,
+    D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = 38,
+    D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = 39,
+    D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = 40,
+    D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = 41,
+    D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = 42,
+    D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = 43,
+    D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = 44,
+    D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = 45,
+    D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = 46,
+    D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = 47,
+    D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = 48,
+    D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = 49,
+    D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = 50,
+    D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = 51,
+    D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = 52,
+    D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = 53,
+    D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = 54,
+    D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = 55,
+    D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = 56,
+    D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = 57,
+    D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = 58,
+    D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = 59,
+    D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = 60,
+    D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = 61,
+    D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = 62,
+    D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = 63,
+    D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64
+} D3D_PRIMITIVE_TOPOLOGY;
+typedef enum D3D_FEATURE_LEVEL {
+    D3D_FEATURE_LEVEL_9_1 = 0x9100,
+    D3D_FEATURE_LEVEL_9_2 = 0x9200,
+    D3D_FEATURE_LEVEL_9_3 = 0x9300,
+    D3D_FEATURE_LEVEL_10_0 = 0xa000,
+    D3D_FEATURE_LEVEL_10_1 = 0xa100,
+    D3D_FEATURE_LEVEL_11_0 = 0xb000,
+    D3D_FEATURE_LEVEL_11_1 = 0xb100,
+    D3D_FEATURE_LEVEL_12_0 = 0xc000,
+    D3D_FEATURE_LEVEL_12_1 = 0xc100
+} D3D_FEATURE_LEVEL;
+/*****************************************************************************
+ * ID3D10Blob interface
+ */
+#ifndef __ID3D10Blob_INTERFACE_DEFINED__
+#define __ID3D10Blob_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_ID3D10Blob, 0x8ba5fb08, 0x5195, 0x40e2, 0xac,0x58, 0x0d,0x98,0x9c,0x3a,0x01,0x02);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("8ba5fb08-5195-40e2-ac58-0d989c3a0102")
+ID3D10Blob : public IUnknown
+{
+    virtual void * STDMETHODCALLTYPE GetBufferPointer(
+        ) = 0;
+
+    virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ID3D10Blob, 0x8ba5fb08, 0x5195, 0x40e2, 0xac,0x58, 0x0d,0x98,0x9c,0x3a,0x01,0x02)
+#endif
+#else
+typedef struct ID3D10BlobVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        ID3D10Blob *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        ID3D10Blob *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        ID3D10Blob *This);
+
+    /*** ID3D10Blob methods ***/
+    void * (STDMETHODCALLTYPE *GetBufferPointer)(
+        ID3D10Blob *This);
+
+    SIZE_T (STDMETHODCALLTYPE *GetBufferSize)(
+        ID3D10Blob *This);
+
+    END_INTERFACE
+} ID3D10BlobVtbl;
+
+interface ID3D10Blob {
+    CONST_VTBL ID3D10BlobVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define ID3D10Blob_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define ID3D10Blob_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define ID3D10Blob_Release(This) (This)->lpVtbl->Release(This)
+/*** ID3D10Blob methods ***/
+#define ID3D10Blob_GetBufferPointer(This) (This)->lpVtbl->GetBufferPointer(This)
+#define ID3D10Blob_GetBufferSize(This) (This)->lpVtbl->GetBufferSize(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT ID3D10Blob_QueryInterface(ID3D10Blob* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG ID3D10Blob_AddRef(ID3D10Blob* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG ID3D10Blob_Release(ID3D10Blob* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** ID3D10Blob methods ***/
+static FORCEINLINE void * ID3D10Blob_GetBufferPointer(ID3D10Blob* This) {
+    return This->lpVtbl->GetBufferPointer(This);
+}
+static FORCEINLINE SIZE_T ID3D10Blob_GetBufferSize(ID3D10Blob* This) {
+    return This->lpVtbl->GetBufferSize(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __ID3D10Blob_INTERFACE_DEFINED__ */
+
+typedef ID3D10Blob ID3DBlob;
+#define IID_ID3DBlob IID_ID3D10Blob
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_d3dcommon_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_d3dcommon.idl b/dlls/vkd3d/include/vkd3d_d3dcommon.idl
new file mode 100644
index 00000000000..8bfa567c538
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_d3dcommon.idl
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_windows.h";
+
+#include "vkd3d_unknown.idl"
+
+typedef enum D3D_PRIMITIVE_TOPOLOGY
+{
+    D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
+    D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
+    D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
+    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
+    D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
+    D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
+    D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
+    D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
+    D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST,
+    D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST,
+} D3D_PRIMITIVE_TOPOLOGY;
+
+typedef enum D3D_FEATURE_LEVEL
+{
+    D3D_FEATURE_LEVEL_9_1 = 0x9100,
+    D3D_FEATURE_LEVEL_9_2 = 0x9200,
+    D3D_FEATURE_LEVEL_9_3 = 0x9300,
+    D3D_FEATURE_LEVEL_10_0 = 0xa000,
+    D3D_FEATURE_LEVEL_10_1 = 0xa100,
+    D3D_FEATURE_LEVEL_11_0 = 0xb000,
+    D3D_FEATURE_LEVEL_11_1 = 0xb100,
+    D3D_FEATURE_LEVEL_12_0 = 0xc000,
+    D3D_FEATURE_LEVEL_12_1 = 0xc100,
+} D3D_FEATURE_LEVEL;
+
+[
+    uuid(8ba5fb08-5195-40e2-ac58-0d989c3a0102),
+    object,
+    local,
+    pointer_default(unique)
+]
+interface ID3D10Blob : IUnknown
+{
+    void *GetBufferPointer();
+    SIZE_T GetBufferSize();
+}
+
+typedef ID3D10Blob ID3DBlob;
+cpp_quote("#define IID_ID3DBlob IID_ID3D10Blob")
diff --git a/dlls/vkd3d/include/vkd3d_dxgi.h b/dlls/vkd3d/include/vkd3d_dxgi.h
new file mode 100644
index 00000000000..89926cb524a
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi.h
@@ -0,0 +1,1237 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgi.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgi_h__
+#define __vkd3d_dxgi_h__
+
+/* Forward declarations */
+
+#ifndef __IUnknown_FWD_DEFINED__
+#define __IUnknown_FWD_DEFINED__
+typedef interface IUnknown IUnknown;
+#ifdef __cplusplus
+interface IUnknown;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIObject_FWD_DEFINED__
+#define __IDXGIObject_FWD_DEFINED__
+typedef interface IDXGIObject IDXGIObject;
+#ifdef __cplusplus
+interface IDXGIObject;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIDeviceSubObject_FWD_DEFINED__
+#define __IDXGIDeviceSubObject_FWD_DEFINED__
+typedef interface IDXGIDeviceSubObject IDXGIDeviceSubObject;
+#ifdef __cplusplus
+interface IDXGIDeviceSubObject;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIAdapter_FWD_DEFINED__
+#define __IDXGIAdapter_FWD_DEFINED__
+typedef interface IDXGIAdapter IDXGIAdapter;
+#ifdef __cplusplus
+interface IDXGIAdapter;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGISwapChain_FWD_DEFINED__
+#define __IDXGISwapChain_FWD_DEFINED__
+typedef interface IDXGISwapChain IDXGISwapChain;
+#ifdef __cplusplus
+interface IDXGISwapChain;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIFactory_FWD_DEFINED__
+#define __IDXGIFactory_FWD_DEFINED__
+typedef interface IDXGIFactory IDXGIFactory;
+#ifdef __cplusplus
+interface IDXGIFactory;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIFactory1_FWD_DEFINED__
+#define __IDXGIFactory1_FWD_DEFINED__
+typedef interface IDXGIFactory1 IDXGIFactory1;
+#ifdef __cplusplus
+interface IDXGIFactory1;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_dxgitype.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __VKD3D_UNKNOWN_H
+#define __VKD3D_UNKNOWN_H
+#if 0
+typedef IID *REFIID;
+typedef IID *REFGUID;
+#endif
+#if !defined(_WIN32)
+typedef void *HWND;
+typedef void *HMODULE;
+typedef struct LUID {
+    DWORD LowPart;
+    LONG HighPart;
+} LUID;
+typedef struct _RECT {
+    LONG left;
+    LONG top;
+    LONG right;
+    LONG bottom;
+} RECT;
+#endif
+/*****************************************************************************
+ * IUnknown interface
+ */
+#ifndef __IUnknown_INTERFACE_DEFINED__
+#define __IUnknown_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("00000000-0000-0000-c000-000000000046")
+IUnknown
+{
+
+    BEGIN_INTERFACE
+
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+        REFIID riid,
+        void **object) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE AddRef(
+        ) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE Release(
+        ) = 0;
+
+    END_INTERFACE
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IUnknown, 0x00000000, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46)
+#endif
+#else
+typedef struct IUnknownVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IUnknown *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IUnknown *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IUnknown *This);
+
+    END_INTERFACE
+} IUnknownVtbl;
+
+interface IUnknown {
+    CONST_VTBL IUnknownVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IUnknown_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IUnknown_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IUnknown_Release(This) (This)->lpVtbl->Release(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IUnknown_QueryInterface(IUnknown* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IUnknown_AddRef(IUnknown* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IUnknown_Release(IUnknown* This) {
+    return This->lpVtbl->Release(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IUnknown_INTERFACE_DEFINED__ */
+
+#endif   /* __VKD3D_UNKNOWN_H */
+typedef enum DXGI_SWAP_EFFECT {
+    DXGI_SWAP_EFFECT_DISCARD = 0x0,
+    DXGI_SWAP_EFFECT_SEQUENTIAL = 0x1,
+    DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 0x3,
+    DXGI_SWAP_EFFECT_FLIP_DISCARD = 0x4
+} DXGI_SWAP_EFFECT;
+typedef enum DXGI_MODE_ROTATION {
+    DXGI_MODE_ROTATION_UNSPECIFIED = 0x0,
+    DXGI_MODE_ROTATION_IDENTITY = 0x1,
+    DXGI_MODE_ROTATION_ROTATE90 = 0x2,
+    DXGI_MODE_ROTATION_ROTATE180 = 0x3,
+    DXGI_MODE_ROTATION_ROTATE270 = 0x4
+} DXGI_MODE_ROTATION;
+#ifndef __IDXGIAdapter1_FWD_DEFINED__
+#define __IDXGIAdapter1_FWD_DEFINED__
+typedef interface IDXGIAdapter1 IDXGIAdapter1;
+#ifdef __cplusplus
+interface IDXGIAdapter1;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIOutput_FWD_DEFINED__
+#define __IDXGIOutput_FWD_DEFINED__
+typedef interface IDXGIOutput IDXGIOutput;
+#ifdef __cplusplus
+interface IDXGIOutput;
+#endif /* __cplusplus */
+#endif
+
+typedef struct DXGI_SWAP_CHAIN_DESC DXGI_SWAP_CHAIN_DESC;
+typedef struct DXGI_FRAME_STATISTICS DXGI_FRAME_STATISTICS;
+typedef UINT DXGI_USAGE;
+#define DXGI_USAGE_SHADER_INPUT (0x10)
+
+#define DXGI_USAGE_RENDER_TARGET_OUTPUT (0x20)
+
+#define DXGI_USAGE_BACK_BUFFER (0x40)
+
+#define DXGI_USAGE_SHARED (0x80)
+
+#define DXGI_USAGE_READ_ONLY (0x100)
+
+#define DXGI_USAGE_DISCARD_ON_PRESENT (0x200)
+
+#define DXGI_USAGE_UNORDERED_ACCESS (0x400)
+
+typedef struct DXGI_ADAPTER_DESC {
+    WCHAR Description[128];
+    UINT VendorId;
+    UINT DeviceId;
+    UINT SubSysId;
+    UINT Revision;
+    SIZE_T DedicatedVideoMemory;
+    SIZE_T DedicatedSystemMemory;
+    SIZE_T SharedSystemMemory;
+    LUID AdapterLuid;
+} DXGI_ADAPTER_DESC;
+/*****************************************************************************
+ * IDXGIObject interface
+ */
+#ifndef __IDXGIObject_INTERFACE_DEFINED__
+#define __IDXGIObject_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b,0xe0, 0x28,0xeb,0x43,0xa6,0x7a,0x2e);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("aec22fb8-76f3-4639-9be0-28eb43a67a2e")
+IDXGIObject : public IUnknown
+{
+    virtual HRESULT STDMETHODCALLTYPE SetPrivateData(
+        REFGUID name,
+        UINT data_size,
+        const void *data) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetPrivateDataInterface(
+        REFGUID name,
+        const IUnknown *unknown) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetPrivateData(
+        REFGUID name,
+        UINT *data_size,
+        void *data) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetParent(
+        REFIID riid,
+        void **parent) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b,0xe0, 0x28,0xeb,0x43,0xa6,0x7a,0x2e)
+#endif
+#else
+typedef struct IDXGIObjectVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIObject *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIObject *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIObject *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIObject *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIObject *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIObject *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIObject *This,
+        REFIID riid,
+        void **parent);
+
+    END_INTERFACE
+} IDXGIObjectVtbl;
+
+interface IDXGIObject {
+    CONST_VTBL IDXGIObjectVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIObject_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIObject_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIObject_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIObject_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIObject_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIObject_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIObject_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIObject_QueryInterface(IDXGIObject* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIObject_AddRef(IDXGIObject* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIObject_Release(IDXGIObject* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIObject_SetPrivateData(IDXGIObject* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIObject_GetPrivateDataInterface(IDXGIObject* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIObject_GetPrivateData(IDXGIObject* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIObject_GetParent(IDXGIObject* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIObject_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIDeviceSubObject interface
+ */
+#ifndef __IDXGIDeviceSubObject_INTERFACE_DEFINED__
+#define __IDXGIDeviceSubObject_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb,0x6c, 0x18,0xd6,0x29,0x92,0xf1,0xa6);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("3d3e0379-f9de-4d58-bb6c-18d62992f1a6")
+IDXGIDeviceSubObject : public IDXGIObject
+{
+    virtual HRESULT STDMETHODCALLTYPE GetDevice(
+        REFIID riid,
+        void **device) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb,0x6c, 0x18,0xd6,0x29,0x92,0xf1,0xa6)
+#endif
+#else
+typedef struct IDXGIDeviceSubObjectVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIDeviceSubObject *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIDeviceSubObject *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIDeviceSubObject *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIDeviceSubObject *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIDeviceSubObject *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIDeviceSubObject *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIDeviceSubObject *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIDeviceSubObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        IDXGIDeviceSubObject *This,
+        REFIID riid,
+        void **device);
+
+    END_INTERFACE
+} IDXGIDeviceSubObjectVtbl;
+
+interface IDXGIDeviceSubObject {
+    CONST_VTBL IDXGIDeviceSubObjectVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIDeviceSubObject_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIDeviceSubObject_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIDeviceSubObject_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIDeviceSubObject_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIDeviceSubObject_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIDeviceSubObject_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIDeviceSubObject_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIDeviceSubObject methods ***/
+#define IDXGIDeviceSubObject_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_QueryInterface(IDXGIDeviceSubObject* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIDeviceSubObject_AddRef(IDXGIDeviceSubObject* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIDeviceSubObject_Release(IDXGIDeviceSubObject* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_SetPrivateData(IDXGIDeviceSubObject* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_GetPrivateDataInterface(IDXGIDeviceSubObject* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_GetPrivateData(IDXGIDeviceSubObject* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_GetParent(IDXGIDeviceSubObject* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIDeviceSubObject methods ***/
+static FORCEINLINE HRESULT IDXGIDeviceSubObject_GetDevice(IDXGIDeviceSubObject* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIDeviceSubObject_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIAdapter interface
+ */
+#ifndef __IDXGIAdapter_INTERFACE_DEFINED__
+#define __IDXGIAdapter_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd,0x14, 0x97,0x98,0xe8,0x53,0x4d,0xc0);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("2411e7e1-12ac-4ccf-bd14-9798e8534dc0")
+IDXGIAdapter : public IDXGIObject
+{
+    virtual HRESULT STDMETHODCALLTYPE EnumOutputs(
+        UINT output_idx,
+        IDXGIOutput **output) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetDesc(
+        DXGI_ADAPTER_DESC *desc) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport(
+        REFGUID guid,
+        void *umd_version) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd,0x14, 0x97,0x98,0xe8,0x53,0x4d,0xc0)
+#endif
+#else
+typedef struct IDXGIAdapterVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIAdapter *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIAdapter *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIAdapter *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIAdapter *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIAdapter *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIAdapter *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIAdapter *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIAdapter methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumOutputs)(
+        IDXGIAdapter *This,
+        UINT output_idx,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *GetDesc)(
+        IDXGIAdapter *This,
+        DXGI_ADAPTER_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *CheckInterfaceSupport)(
+        IDXGIAdapter *This,
+        REFGUID guid,
+        void *umd_version);
+
+    END_INTERFACE
+} IDXGIAdapterVtbl;
+
+interface IDXGIAdapter {
+    CONST_VTBL IDXGIAdapterVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIAdapter_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIAdapter_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIAdapter_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIAdapter_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIAdapter_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIAdapter_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIAdapter_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIAdapter methods ***/
+#define IDXGIAdapter_EnumOutputs(This,output_idx,output) (This)->lpVtbl->EnumOutputs(This,output_idx,output)
+#define IDXGIAdapter_GetDesc(This,desc) (This)->lpVtbl->GetDesc(This,desc)
+#define IDXGIAdapter_CheckInterfaceSupport(This,guid,umd_version) (This)->lpVtbl->CheckInterfaceSupport(This,guid,umd_version)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIAdapter_QueryInterface(IDXGIAdapter* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIAdapter_AddRef(IDXGIAdapter* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIAdapter_Release(IDXGIAdapter* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIAdapter_SetPrivateData(IDXGIAdapter* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIAdapter_GetPrivateDataInterface(IDXGIAdapter* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIAdapter_GetPrivateData(IDXGIAdapter* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIAdapter_GetParent(IDXGIAdapter* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIAdapter methods ***/
+static FORCEINLINE HRESULT IDXGIAdapter_EnumOutputs(IDXGIAdapter* This,UINT output_idx,IDXGIOutput **output) {
+    return This->lpVtbl->EnumOutputs(This,output_idx,output);
+}
+static FORCEINLINE HRESULT IDXGIAdapter_GetDesc(IDXGIAdapter* This,DXGI_ADAPTER_DESC *desc) {
+    return This->lpVtbl->GetDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGIAdapter_CheckInterfaceSupport(IDXGIAdapter* This,REFGUID guid,void *umd_version) {
+    return This->lpVtbl->CheckInterfaceSupport(This,guid,umd_version);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIAdapter_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGISwapChain interface
+ */
+#ifndef __IDXGISwapChain_INTERFACE_DEFINED__
+#define __IDXGISwapChain_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa,0x04, 0x6a,0x9d,0x23,0xb8,0x88,0x6a);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("310d36a0-d2e7-4c0a-aa04-6a9d23b8886a")
+IDXGISwapChain : public IDXGIDeviceSubObject
+{
+    virtual HRESULT STDMETHODCALLTYPE Present(
+        UINT sync_interval,
+        UINT flags) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetBuffer(
+        UINT buffer_idx,
+        REFIID riid,
+        void **surface) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(
+        BOOL fullscreen,
+        IDXGIOutput *target) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(
+        BOOL *fullscreen,
+        IDXGIOutput **target) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetDesc(
+        DXGI_SWAP_CHAIN_DESC *desc) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ResizeTarget(
+        const DXGI_MODE_DESC *desc) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(
+        IDXGIOutput **output) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
+        DXGI_FRAME_STATISTICS *stats) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(
+        UINT *last_present_count) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa,0x04, 0x6a,0x9d,0x23,0xb8,0x88,0x6a)
+#endif
+#else
+typedef struct IDXGISwapChainVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGISwapChain *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGISwapChain *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGISwapChain *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGISwapChain *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGISwapChain *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGISwapChain *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGISwapChain *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIDeviceSubObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        IDXGISwapChain *This,
+        REFIID riid,
+        void **device);
+
+    /*** IDXGISwapChain methods ***/
+    HRESULT (STDMETHODCALLTYPE *Present)(
+        IDXGISwapChain *This,
+        UINT sync_interval,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetBuffer)(
+        IDXGISwapChain *This,
+        UINT buffer_idx,
+        REFIID riid,
+        void **surface);
+
+    HRESULT (STDMETHODCALLTYPE *SetFullscreenState)(
+        IDXGISwapChain *This,
+        BOOL fullscreen,
+        IDXGIOutput *target);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenState)(
+        IDXGISwapChain *This,
+        BOOL *fullscreen,
+        IDXGIOutput **target);
+
+    HRESULT (STDMETHODCALLTYPE *GetDesc)(
+        IDXGISwapChain *This,
+        DXGI_SWAP_CHAIN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeBuffers)(
+        IDXGISwapChain *This,
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeTarget)(
+        IDXGISwapChain *This,
+        const DXGI_MODE_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetContainingOutput)(
+        IDXGISwapChain *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *GetFrameStatistics)(
+        IDXGISwapChain *This,
+        DXGI_FRAME_STATISTICS *stats);
+
+    HRESULT (STDMETHODCALLTYPE *GetLastPresentCount)(
+        IDXGISwapChain *This,
+        UINT *last_present_count);
+
+    END_INTERFACE
+} IDXGISwapChainVtbl;
+
+interface IDXGISwapChain {
+    CONST_VTBL IDXGISwapChainVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGISwapChain_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGISwapChain_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGISwapChain_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGISwapChain_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGISwapChain_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIDeviceSubObject methods ***/
+#define IDXGISwapChain_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** IDXGISwapChain methods ***/
+#define IDXGISwapChain_Present(This,sync_interval,flags) (This)->lpVtbl->Present(This,sync_interval,flags)
+#define IDXGISwapChain_GetBuffer(This,buffer_idx,riid,surface) (This)->lpVtbl->GetBuffer(This,buffer_idx,riid,surface)
+#define IDXGISwapChain_SetFullscreenState(This,fullscreen,target) (This)->lpVtbl->SetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain_GetFullscreenState(This,fullscreen,target) (This)->lpVtbl->GetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain_GetDesc(This,desc) (This)->lpVtbl->GetDesc(This,desc)
+#define IDXGISwapChain_ResizeBuffers(This,buffer_count,width,height,format,flags) (This)->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags)
+#define IDXGISwapChain_ResizeTarget(This,desc) (This)->lpVtbl->ResizeTarget(This,desc)
+#define IDXGISwapChain_GetContainingOutput(This,output) (This)->lpVtbl->GetContainingOutput(This,output)
+#define IDXGISwapChain_GetFrameStatistics(This,stats) (This)->lpVtbl->GetFrameStatistics(This,stats)
+#define IDXGISwapChain_GetLastPresentCount(This,last_present_count) (This)->lpVtbl->GetLastPresentCount(This,last_present_count)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain_QueryInterface(IDXGISwapChain* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGISwapChain_AddRef(IDXGISwapChain* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGISwapChain_Release(IDXGISwapChain* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain_SetPrivateData(IDXGISwapChain* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetPrivateDataInterface(IDXGISwapChain* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetPrivateData(IDXGISwapChain* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetParent(IDXGISwapChain* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIDeviceSubObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain_GetDevice(IDXGISwapChain* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** IDXGISwapChain methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain_Present(IDXGISwapChain* This,UINT sync_interval,UINT flags) {
+    return This->lpVtbl->Present(This,sync_interval,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetBuffer(IDXGISwapChain* This,UINT buffer_idx,REFIID riid,void **surface) {
+    return This->lpVtbl->GetBuffer(This,buffer_idx,riid,surface);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_SetFullscreenState(IDXGISwapChain* This,BOOL fullscreen,IDXGIOutput *target) {
+    return This->lpVtbl->SetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetFullscreenState(IDXGISwapChain* This,BOOL *fullscreen,IDXGIOutput **target) {
+    return This->lpVtbl->GetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetDesc(IDXGISwapChain* This,DXGI_SWAP_CHAIN_DESC *desc) {
+    return This->lpVtbl->GetDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_ResizeBuffers(IDXGISwapChain* This,UINT buffer_count,UINT width,UINT height,DXGI_FORMAT format,UINT flags) {
+    return This->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_ResizeTarget(IDXGISwapChain* This,const DXGI_MODE_DESC *desc) {
+    return This->lpVtbl->ResizeTarget(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetContainingOutput(IDXGISwapChain* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetContainingOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetFrameStatistics(IDXGISwapChain* This,DXGI_FRAME_STATISTICS *stats) {
+    return This->lpVtbl->GetFrameStatistics(This,stats);
+}
+static FORCEINLINE HRESULT IDXGISwapChain_GetLastPresentCount(IDXGISwapChain* This,UINT *last_present_count) {
+    return This->lpVtbl->GetLastPresentCount(This,last_present_count);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGISwapChain_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIFactory interface
+ */
+#ifndef __IDXGIFactory_INTERFACE_DEFINED__
+#define __IDXGIFactory_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2,0x1a, 0xc9,0xae,0x32,0x1a,0xe3,0x69);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("7b7166ec-21c7-44ae-b21a-c9ae321ae369")
+IDXGIFactory : public IDXGIObject
+{
+    virtual HRESULT STDMETHODCALLTYPE EnumAdapters(
+        UINT adapter_idx,
+        IDXGIAdapter **adapter) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
+        HWND hwnd,
+        UINT flags) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(
+        HWND *hwnd) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
+        HMODULE hmodule,
+        IDXGIAdapter **adapter) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2,0x1a, 0xc9,0xae,0x32,0x1a,0xe3,0x69)
+#endif
+#else
+typedef struct IDXGIFactoryVtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIFactory *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIFactory *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIFactory *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIFactory *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIFactory *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIFactory *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIFactory *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIFactory methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters)(
+        IDXGIFactory *This,
+        UINT adapter_idx,
+        IDXGIAdapter **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *MakeWindowAssociation)(
+        IDXGIFactory *This,
+        HWND hwnd,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetWindowAssociation)(
+        IDXGIFactory *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChain)(
+        IDXGIFactory *This,
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSoftwareAdapter)(
+        IDXGIFactory *This,
+        HMODULE hmodule,
+        IDXGIAdapter **adapter);
+
+    END_INTERFACE
+} IDXGIFactoryVtbl;
+
+interface IDXGIFactory {
+    CONST_VTBL IDXGIFactoryVtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIFactory_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIFactory_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIFactory_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIFactory_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIFactory_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIFactory_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIFactory_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIFactory methods ***/
+#define IDXGIFactory_EnumAdapters(This,adapter_idx,adapter) (This)->lpVtbl->EnumAdapters(This,adapter_idx,adapter)
+#define IDXGIFactory_MakeWindowAssociation(This,hwnd,flags) (This)->lpVtbl->MakeWindowAssociation(This,hwnd,flags)
+#define IDXGIFactory_GetWindowAssociation(This,hwnd) (This)->lpVtbl->GetWindowAssociation(This,hwnd)
+#define IDXGIFactory_CreateSwapChain(This,device,desc,swapchain) (This)->lpVtbl->CreateSwapChain(This,device,desc,swapchain)
+#define IDXGIFactory_CreateSoftwareAdapter(This,hmodule,adapter) (This)->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIFactory_QueryInterface(IDXGIFactory* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIFactory_AddRef(IDXGIFactory* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIFactory_Release(IDXGIFactory* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIFactory_SetPrivateData(IDXGIFactory* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory_GetPrivateDataInterface(IDXGIFactory* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIFactory_GetPrivateData(IDXGIFactory* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory_GetParent(IDXGIFactory* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIFactory methods ***/
+static FORCEINLINE HRESULT IDXGIFactory_EnumAdapters(IDXGIFactory* This,UINT adapter_idx,IDXGIAdapter **adapter) {
+    return This->lpVtbl->EnumAdapters(This,adapter_idx,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory_MakeWindowAssociation(IDXGIFactory* This,HWND hwnd,UINT flags) {
+    return This->lpVtbl->MakeWindowAssociation(This,hwnd,flags);
+}
+static FORCEINLINE HRESULT IDXGIFactory_GetWindowAssociation(IDXGIFactory* This,HWND *hwnd) {
+    return This->lpVtbl->GetWindowAssociation(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGIFactory_CreateSwapChain(IDXGIFactory* This,IUnknown *device,DXGI_SWAP_CHAIN_DESC *desc,IDXGISwapChain **swapchain) {
+    return This->lpVtbl->CreateSwapChain(This,device,desc,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory_CreateSoftwareAdapter(IDXGIFactory* This,HMODULE hmodule,IDXGIAdapter **adapter) {
+    return This->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIFactory_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIFactory1 interface
+ */
+#ifndef __IDXGIFactory1_INTERFACE_DEFINED__
+#define __IDXGIFactory1_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8,0x29, 0x25,0x3c,0x83,0xd1,0xb3,0x87);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("770aae78-f26f-4dba-a829-253c83d1b387")
+IDXGIFactory1 : public IDXGIFactory
+{
+    virtual HRESULT STDMETHODCALLTYPE EnumAdapters1(
+        UINT adapter_idx,
+        IDXGIAdapter1 **adpter) = 0;
+
+    virtual BOOL STDMETHODCALLTYPE IsCurrent(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8,0x29, 0x25,0x3c,0x83,0xd1,0xb3,0x87)
+#endif
+#else
+typedef struct IDXGIFactory1Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIFactory1 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIFactory1 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIFactory1 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIFactory1 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIFactory1 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIFactory1 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIFactory1 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIFactory methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters)(
+        IDXGIFactory1 *This,
+        UINT adapter_idx,
+        IDXGIAdapter **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *MakeWindowAssociation)(
+        IDXGIFactory1 *This,
+        HWND hwnd,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetWindowAssociation)(
+        IDXGIFactory1 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChain)(
+        IDXGIFactory1 *This,
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSoftwareAdapter)(
+        IDXGIFactory1 *This,
+        HMODULE hmodule,
+        IDXGIAdapter **adapter);
+
+    /*** IDXGIFactory1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters1)(
+        IDXGIFactory1 *This,
+        UINT adapter_idx,
+        IDXGIAdapter1 **adpter);
+
+    BOOL (STDMETHODCALLTYPE *IsCurrent)(
+        IDXGIFactory1 *This);
+
+    END_INTERFACE
+} IDXGIFactory1Vtbl;
+
+interface IDXGIFactory1 {
+    CONST_VTBL IDXGIFactory1Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIFactory1_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIFactory1_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIFactory1_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIFactory1_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIFactory1_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIFactory1_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIFactory1_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIFactory methods ***/
+#define IDXGIFactory1_EnumAdapters(This,adapter_idx,adapter) (This)->lpVtbl->EnumAdapters(This,adapter_idx,adapter)
+#define IDXGIFactory1_MakeWindowAssociation(This,hwnd,flags) (This)->lpVtbl->MakeWindowAssociation(This,hwnd,flags)
+#define IDXGIFactory1_GetWindowAssociation(This,hwnd) (This)->lpVtbl->GetWindowAssociation(This,hwnd)
+#define IDXGIFactory1_CreateSwapChain(This,device,desc,swapchain) (This)->lpVtbl->CreateSwapChain(This,device,desc,swapchain)
+#define IDXGIFactory1_CreateSoftwareAdapter(This,hmodule,adapter) (This)->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter)
+/*** IDXGIFactory1 methods ***/
+#define IDXGIFactory1_EnumAdapters1(This,adapter_idx,adpter) (This)->lpVtbl->EnumAdapters1(This,adapter_idx,adpter)
+#define IDXGIFactory1_IsCurrent(This) (This)->lpVtbl->IsCurrent(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIFactory1_QueryInterface(IDXGIFactory1* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIFactory1_AddRef(IDXGIFactory1* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIFactory1_Release(IDXGIFactory1* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIFactory1_SetPrivateData(IDXGIFactory1* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_GetPrivateDataInterface(IDXGIFactory1* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_GetPrivateData(IDXGIFactory1* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_GetParent(IDXGIFactory1* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIFactory methods ***/
+static FORCEINLINE HRESULT IDXGIFactory1_EnumAdapters(IDXGIFactory1* This,UINT adapter_idx,IDXGIAdapter **adapter) {
+    return This->lpVtbl->EnumAdapters(This,adapter_idx,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_MakeWindowAssociation(IDXGIFactory1* This,HWND hwnd,UINT flags) {
+    return This->lpVtbl->MakeWindowAssociation(This,hwnd,flags);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_GetWindowAssociation(IDXGIFactory1* This,HWND *hwnd) {
+    return This->lpVtbl->GetWindowAssociation(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_CreateSwapChain(IDXGIFactory1* This,IUnknown *device,DXGI_SWAP_CHAIN_DESC *desc,IDXGISwapChain **swapchain) {
+    return This->lpVtbl->CreateSwapChain(This,device,desc,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory1_CreateSoftwareAdapter(IDXGIFactory1* This,HMODULE hmodule,IDXGIAdapter **adapter) {
+    return This->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter);
+}
+/*** IDXGIFactory1 methods ***/
+static FORCEINLINE HRESULT IDXGIFactory1_EnumAdapters1(IDXGIFactory1* This,UINT adapter_idx,IDXGIAdapter1 **adpter) {
+    return This->lpVtbl->EnumAdapters1(This,adapter_idx,adpter);
+}
+static FORCEINLINE BOOL IDXGIFactory1_IsCurrent(IDXGIFactory1* This) {
+    return This->lpVtbl->IsCurrent(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIFactory1_INTERFACE_DEFINED__ */
+
+HRESULT __stdcall  CreateDXGIFactory(REFIID riid,void **factory);
+
+HRESULT __stdcall  CreateDXGIFactory1(REFIID riid,void **factory);
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgi_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgi.idl b/dlls/vkd3d/include/vkd3d_dxgi.idl
new file mode 100644
index 00000000000..7e07a78dd36
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi.idl
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_dxgitype.idl";
+
+#include "vkd3d_unknown.idl"
+
+typedef enum DXGI_SWAP_EFFECT
+{
+    DXGI_SWAP_EFFECT_DISCARD         = 0x0,
+    DXGI_SWAP_EFFECT_SEQUENTIAL      = 0x1,
+    DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 0x3,
+    DXGI_SWAP_EFFECT_FLIP_DISCARD    = 0x4,
+} DXGI_SWAP_EFFECT;
+
+typedef enum DXGI_MODE_ROTATION
+{
+    DXGI_MODE_ROTATION_UNSPECIFIED = 0x0,
+    DXGI_MODE_ROTATION_IDENTITY    = 0x1,
+    DXGI_MODE_ROTATION_ROTATE90    = 0x2,
+    DXGI_MODE_ROTATION_ROTATE180   = 0x3,
+    DXGI_MODE_ROTATION_ROTATE270   = 0x4,
+} DXGI_MODE_ROTATION;
+
+interface IDXGIAdapter1;
+interface IDXGIOutput;
+typedef struct DXGI_SWAP_CHAIN_DESC DXGI_SWAP_CHAIN_DESC;
+typedef struct DXGI_FRAME_STATISTICS DXGI_FRAME_STATISTICS;
+
+typedef UINT DXGI_USAGE;
+
+const DXGI_USAGE DXGI_USAGE_SHADER_INPUT         = 0x00000010ul;
+const DXGI_USAGE DXGI_USAGE_RENDER_TARGET_OUTPUT = 0x00000020ul;
+const DXGI_USAGE DXGI_USAGE_BACK_BUFFER          = 0x00000040ul;
+const DXGI_USAGE DXGI_USAGE_SHARED               = 0x00000080ul;
+const DXGI_USAGE DXGI_USAGE_READ_ONLY            = 0x00000100ul;
+const DXGI_USAGE DXGI_USAGE_DISCARD_ON_PRESENT   = 0x00000200ul;
+const DXGI_USAGE DXGI_USAGE_UNORDERED_ACCESS     = 0x00000400ul;
+
+typedef struct DXGI_ADAPTER_DESC
+{
+    WCHAR Description[128];
+    UINT VendorId;
+    UINT DeviceId;
+    UINT SubSysId;
+    UINT Revision;
+    SIZE_T DedicatedVideoMemory;
+    SIZE_T DedicatedSystemMemory;
+    SIZE_T SharedSystemMemory;
+    LUID AdapterLuid;
+} DXGI_ADAPTER_DESC;
+
+[
+    local,
+    object,
+    uuid(aec22fb8-76f3-4639-9be0-28eb43a67a2e),
+    pointer_default(unique)
+]
+interface IDXGIObject : IUnknown
+{
+    HRESULT SetPrivateData(REFGUID name, UINT data_size, const void *data);
+    HRESULT GetPrivateDataInterface(REFGUID name, const IUnknown *unknown);
+    HRESULT GetPrivateData(REFGUID name, UINT *data_size, void *data);
+    HRESULT GetParent(REFIID riid, void **parent);
+}
+
+[
+    local,
+    object,
+    uuid(3d3e0379-f9de-4d58-bb6c-18d62992f1a6),
+    pointer_default(unique)
+]
+interface IDXGIDeviceSubObject : IDXGIObject
+{
+    HRESULT GetDevice(REFIID riid, void **device);
+}
+
+[
+    object,
+    local,
+    uuid(2411e7e1-12ac-4ccf-bd14-9798e8534dc0)
+]
+interface IDXGIAdapter : IDXGIObject
+{
+    HRESULT EnumOutputs(UINT output_idx, IDXGIOutput **output);
+    HRESULT GetDesc(DXGI_ADAPTER_DESC *desc);
+    HRESULT CheckInterfaceSupport(REFGUID guid, void *umd_version);
+}
+
+[
+    local,
+    object,
+    uuid(310d36a0-d2e7-4c0a-aa04-6a9d23b8886a),
+    pointer_default(unique)
+]
+interface IDXGISwapChain : IDXGIDeviceSubObject
+{
+    HRESULT Present(UINT sync_interval, UINT flags);
+    HRESULT GetBuffer(UINT buffer_idx, REFIID riid, void **surface);
+    HRESULT SetFullscreenState(BOOL fullscreen, IDXGIOutput *target);
+    HRESULT GetFullscreenState(BOOL *fullscreen, IDXGIOutput **target);
+    HRESULT GetDesc(DXGI_SWAP_CHAIN_DESC *desc);
+    HRESULT ResizeBuffers(UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags);
+    HRESULT ResizeTarget(const DXGI_MODE_DESC *desc);
+    HRESULT GetContainingOutput(IDXGIOutput **output);
+    HRESULT GetFrameStatistics(DXGI_FRAME_STATISTICS *stats);
+    HRESULT GetLastPresentCount(UINT *last_present_count);
+}
+
+[
+    local,
+    object,
+    uuid(7b7166ec-21c7-44ae-b21a-c9ae321ae369),
+    pointer_default(unique)
+]
+interface IDXGIFactory : IDXGIObject
+{
+    HRESULT EnumAdapters(UINT adapter_idx, IDXGIAdapter **adapter);
+    HRESULT MakeWindowAssociation(HWND hwnd, UINT flags);
+    HRESULT GetWindowAssociation(HWND *hwnd);
+    HRESULT CreateSwapChain(IUnknown *device, DXGI_SWAP_CHAIN_DESC *desc, IDXGISwapChain **swapchain);
+    HRESULT CreateSoftwareAdapter(HMODULE hmodule, IDXGIAdapter **adapter);
+}
+
+[
+    local,
+    object,
+    uuid(770aae78-f26f-4dba-a829-253c83d1b387),
+    pointer_default(unique)
+]
+interface IDXGIFactory1 : IDXGIFactory
+{
+    HRESULT EnumAdapters1(UINT adapter_idx, IDXGIAdapter1 **adpter);
+    BOOL IsCurrent();
+}
+
+[local] HRESULT __stdcall CreateDXGIFactory(REFIID riid, void **factory);
+[local] HRESULT __stdcall CreateDXGIFactory1(REFIID riid, void **factory);
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_2.h b/dlls/vkd3d/include/vkd3d_dxgi1_2.h
new file mode 100644
index 00000000000..cc37ef815b2
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_2.h
@@ -0,0 +1,751 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgi1_2.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgi1_2_h__
+#define __vkd3d_dxgi1_2_h__
+
+/* Forward declarations */
+
+#ifndef __IDXGISwapChain1_FWD_DEFINED__
+#define __IDXGISwapChain1_FWD_DEFINED__
+typedef interface IDXGISwapChain1 IDXGISwapChain1;
+#ifdef __cplusplus
+interface IDXGISwapChain1;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIFactory2_FWD_DEFINED__
+#define __IDXGIFactory2_FWD_DEFINED__
+typedef interface IDXGIFactory2 IDXGIFactory2;
+#ifdef __cplusplus
+interface IDXGIFactory2;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_dxgi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum DXGI_SCALING {
+    DXGI_SCALING_STRETCH = 0x0,
+    DXGI_SCALING_NONE = 0x1,
+    DXGI_SCALING_ASPECT_RATIO_STRETCH = 0x2,
+    DXGI_SCALING_FORCE_DWORD = 0xffffffff
+} DXGI_SCALING;
+typedef enum DXGI_ALPHA_MODE {
+    DXGI_ALPHA_MODE_UNSPECIFIED = 0x0,
+    DXGI_ALPHA_MODE_PREMULTIPLIED = 0x1,
+    DXGI_ALPHA_MODE_STRAIGHT = 0x2,
+    DXGI_ALPHA_MODE_IGNORE = 0x3,
+    DXGI_ALPHA_MODE_FORCE_DWORD = 0xffffffff
+} DXGI_ALPHA_MODE;
+typedef struct DXGI_SWAP_CHAIN_DESC1 {
+    UINT Width;
+    UINT Height;
+    DXGI_FORMAT Format;
+    BOOL Stereo;
+    DXGI_SAMPLE_DESC SampleDesc;
+    DXGI_USAGE BufferUsage;
+    UINT BufferCount;
+    DXGI_SCALING Scaling;
+    DXGI_SWAP_EFFECT SwapEffect;
+    DXGI_ALPHA_MODE AlphaMode;
+    UINT Flags;
+} DXGI_SWAP_CHAIN_DESC1;
+typedef struct DXGI_SWAP_CHAIN_FULLSCREEN_DESC DXGI_SWAP_CHAIN_FULLSCREEN_DESC;
+typedef struct DXGI_PRESENT_PARAMETERS DXGI_PRESENT_PARAMETERS;
+/*****************************************************************************
+ * IDXGISwapChain1 interface
+ */
+#ifndef __IDXGISwapChain1_INTERFACE_DEFINED__
+#define __IDXGISwapChain1_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98,0x3a, 0x0a,0x55,0xcf,0xe6,0xf4,0xaa);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("790a45f7-0d42-4876-983a-0a55cfe6f4aa")
+IDXGISwapChain1 : public IDXGISwapChain
+{
+    virtual HRESULT STDMETHODCALLTYPE GetDesc1(
+        DXGI_SWAP_CHAIN_DESC1 *desc) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetFullscreenDesc(
+        DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetHwnd(
+        HWND *hwnd) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetCoreWindow(
+        REFIID riid,
+        void **object) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE Present1(
+        UINT sync_interval,
+        UINT flags,
+        const DXGI_PRESENT_PARAMETERS *parameters) = 0;
+
+    virtual BOOL STDMETHODCALLTYPE IsTemporaryMonoSupported(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetRestrictToOutput(
+        IDXGIOutput **output) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetBackgroundColor(
+        const DXGI_RGBA *color) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetBackgroundColor(
+        DXGI_RGBA *color) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetRotation(
+        DXGI_MODE_ROTATION rotation) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetRotation(
+        DXGI_MODE_ROTATION *rotation) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98,0x3a, 0x0a,0x55,0xcf,0xe6,0xf4,0xaa)
+#endif
+#else
+typedef struct IDXGISwapChain1Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGISwapChain1 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGISwapChain1 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGISwapChain1 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGISwapChain1 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGISwapChain1 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGISwapChain1 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGISwapChain1 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIDeviceSubObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        IDXGISwapChain1 *This,
+        REFIID riid,
+        void **device);
+
+    /*** IDXGISwapChain methods ***/
+    HRESULT (STDMETHODCALLTYPE *Present)(
+        IDXGISwapChain1 *This,
+        UINT sync_interval,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetBuffer)(
+        IDXGISwapChain1 *This,
+        UINT buffer_idx,
+        REFIID riid,
+        void **surface);
+
+    HRESULT (STDMETHODCALLTYPE *SetFullscreenState)(
+        IDXGISwapChain1 *This,
+        BOOL fullscreen,
+        IDXGIOutput *target);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenState)(
+        IDXGISwapChain1 *This,
+        BOOL *fullscreen,
+        IDXGIOutput **target);
+
+    HRESULT (STDMETHODCALLTYPE *GetDesc)(
+        IDXGISwapChain1 *This,
+        DXGI_SWAP_CHAIN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeBuffers)(
+        IDXGISwapChain1 *This,
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeTarget)(
+        IDXGISwapChain1 *This,
+        const DXGI_MODE_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetContainingOutput)(
+        IDXGISwapChain1 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *GetFrameStatistics)(
+        IDXGISwapChain1 *This,
+        DXGI_FRAME_STATISTICS *stats);
+
+    HRESULT (STDMETHODCALLTYPE *GetLastPresentCount)(
+        IDXGISwapChain1 *This,
+        UINT *last_present_count);
+
+    /*** IDXGISwapChain1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDesc1)(
+        IDXGISwapChain1 *This,
+        DXGI_SWAP_CHAIN_DESC1 *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenDesc)(
+        IDXGISwapChain1 *This,
+        DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetHwnd)(
+        IDXGISwapChain1 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *GetCoreWindow)(
+        IDXGISwapChain1 *This,
+        REFIID riid,
+        void **object);
+
+    HRESULT (STDMETHODCALLTYPE *Present1)(
+        IDXGISwapChain1 *This,
+        UINT sync_interval,
+        UINT flags,
+        const DXGI_PRESENT_PARAMETERS *parameters);
+
+    BOOL (STDMETHODCALLTYPE *IsTemporaryMonoSupported)(
+        IDXGISwapChain1 *This);
+
+    HRESULT (STDMETHODCALLTYPE *GetRestrictToOutput)(
+        IDXGISwapChain1 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *SetBackgroundColor)(
+        IDXGISwapChain1 *This,
+        const DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *GetBackgroundColor)(
+        IDXGISwapChain1 *This,
+        DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *SetRotation)(
+        IDXGISwapChain1 *This,
+        DXGI_MODE_ROTATION rotation);
+
+    HRESULT (STDMETHODCALLTYPE *GetRotation)(
+        IDXGISwapChain1 *This,
+        DXGI_MODE_ROTATION *rotation);
+
+    END_INTERFACE
+} IDXGISwapChain1Vtbl;
+
+interface IDXGISwapChain1 {
+    CONST_VTBL IDXGISwapChain1Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGISwapChain1_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGISwapChain1_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGISwapChain1_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGISwapChain1_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain1_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGISwapChain1_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain1_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIDeviceSubObject methods ***/
+#define IDXGISwapChain1_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** IDXGISwapChain methods ***/
+#define IDXGISwapChain1_Present(This,sync_interval,flags) (This)->lpVtbl->Present(This,sync_interval,flags)
+#define IDXGISwapChain1_GetBuffer(This,buffer_idx,riid,surface) (This)->lpVtbl->GetBuffer(This,buffer_idx,riid,surface)
+#define IDXGISwapChain1_SetFullscreenState(This,fullscreen,target) (This)->lpVtbl->SetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain1_GetFullscreenState(This,fullscreen,target) (This)->lpVtbl->GetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain1_GetDesc(This,desc) (This)->lpVtbl->GetDesc(This,desc)
+#define IDXGISwapChain1_ResizeBuffers(This,buffer_count,width,height,format,flags) (This)->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags)
+#define IDXGISwapChain1_ResizeTarget(This,desc) (This)->lpVtbl->ResizeTarget(This,desc)
+#define IDXGISwapChain1_GetContainingOutput(This,output) (This)->lpVtbl->GetContainingOutput(This,output)
+#define IDXGISwapChain1_GetFrameStatistics(This,stats) (This)->lpVtbl->GetFrameStatistics(This,stats)
+#define IDXGISwapChain1_GetLastPresentCount(This,last_present_count) (This)->lpVtbl->GetLastPresentCount(This,last_present_count)
+/*** IDXGISwapChain1 methods ***/
+#define IDXGISwapChain1_GetDesc1(This,desc) (This)->lpVtbl->GetDesc1(This,desc)
+#define IDXGISwapChain1_GetFullscreenDesc(This,desc) (This)->lpVtbl->GetFullscreenDesc(This,desc)
+#define IDXGISwapChain1_GetHwnd(This,hwnd) (This)->lpVtbl->GetHwnd(This,hwnd)
+#define IDXGISwapChain1_GetCoreWindow(This,riid,object) (This)->lpVtbl->GetCoreWindow(This,riid,object)
+#define IDXGISwapChain1_Present1(This,sync_interval,flags,parameters) (This)->lpVtbl->Present1(This,sync_interval,flags,parameters)
+#define IDXGISwapChain1_IsTemporaryMonoSupported(This) (This)->lpVtbl->IsTemporaryMonoSupported(This)
+#define IDXGISwapChain1_GetRestrictToOutput(This,output) (This)->lpVtbl->GetRestrictToOutput(This,output)
+#define IDXGISwapChain1_SetBackgroundColor(This,color) (This)->lpVtbl->SetBackgroundColor(This,color)
+#define IDXGISwapChain1_GetBackgroundColor(This,color) (This)->lpVtbl->GetBackgroundColor(This,color)
+#define IDXGISwapChain1_SetRotation(This,rotation) (This)->lpVtbl->SetRotation(This,rotation)
+#define IDXGISwapChain1_GetRotation(This,rotation) (This)->lpVtbl->GetRotation(This,rotation)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain1_QueryInterface(IDXGISwapChain1* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGISwapChain1_AddRef(IDXGISwapChain1* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGISwapChain1_Release(IDXGISwapChain1* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain1_SetPrivateData(IDXGISwapChain1* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetPrivateDataInterface(IDXGISwapChain1* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetPrivateData(IDXGISwapChain1* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetParent(IDXGISwapChain1* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIDeviceSubObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain1_GetDevice(IDXGISwapChain1* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** IDXGISwapChain methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain1_Present(IDXGISwapChain1* This,UINT sync_interval,UINT flags) {
+    return This->lpVtbl->Present(This,sync_interval,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetBuffer(IDXGISwapChain1* This,UINT buffer_idx,REFIID riid,void **surface) {
+    return This->lpVtbl->GetBuffer(This,buffer_idx,riid,surface);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_SetFullscreenState(IDXGISwapChain1* This,BOOL fullscreen,IDXGIOutput *target) {
+    return This->lpVtbl->SetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetFullscreenState(IDXGISwapChain1* This,BOOL *fullscreen,IDXGIOutput **target) {
+    return This->lpVtbl->GetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetDesc(IDXGISwapChain1* This,DXGI_SWAP_CHAIN_DESC *desc) {
+    return This->lpVtbl->GetDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_ResizeBuffers(IDXGISwapChain1* This,UINT buffer_count,UINT width,UINT height,DXGI_FORMAT format,UINT flags) {
+    return This->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_ResizeTarget(IDXGISwapChain1* This,const DXGI_MODE_DESC *desc) {
+    return This->lpVtbl->ResizeTarget(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetContainingOutput(IDXGISwapChain1* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetContainingOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetFrameStatistics(IDXGISwapChain1* This,DXGI_FRAME_STATISTICS *stats) {
+    return This->lpVtbl->GetFrameStatistics(This,stats);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetLastPresentCount(IDXGISwapChain1* This,UINT *last_present_count) {
+    return This->lpVtbl->GetLastPresentCount(This,last_present_count);
+}
+/*** IDXGISwapChain1 methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain1_GetDesc1(IDXGISwapChain1* This,DXGI_SWAP_CHAIN_DESC1 *desc) {
+    return This->lpVtbl->GetDesc1(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetFullscreenDesc(IDXGISwapChain1* This,DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) {
+    return This->lpVtbl->GetFullscreenDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetHwnd(IDXGISwapChain1* This,HWND *hwnd) {
+    return This->lpVtbl->GetHwnd(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetCoreWindow(IDXGISwapChain1* This,REFIID riid,void **object) {
+    return This->lpVtbl->GetCoreWindow(This,riid,object);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_Present1(IDXGISwapChain1* This,UINT sync_interval,UINT flags,const DXGI_PRESENT_PARAMETERS *parameters) {
+    return This->lpVtbl->Present1(This,sync_interval,flags,parameters);
+}
+static FORCEINLINE BOOL IDXGISwapChain1_IsTemporaryMonoSupported(IDXGISwapChain1* This) {
+    return This->lpVtbl->IsTemporaryMonoSupported(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetRestrictToOutput(IDXGISwapChain1* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetRestrictToOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_SetBackgroundColor(IDXGISwapChain1* This,const DXGI_RGBA *color) {
+    return This->lpVtbl->SetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetBackgroundColor(IDXGISwapChain1* This,DXGI_RGBA *color) {
+    return This->lpVtbl->GetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_SetRotation(IDXGISwapChain1* This,DXGI_MODE_ROTATION rotation) {
+    return This->lpVtbl->SetRotation(This,rotation);
+}
+static FORCEINLINE HRESULT IDXGISwapChain1_GetRotation(IDXGISwapChain1* This,DXGI_MODE_ROTATION *rotation) {
+    return This->lpVtbl->GetRotation(This,rotation);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGISwapChain1_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIFactory2 interface
+ */
+#ifndef __IDXGIFactory2_INTERFACE_DEFINED__
+#define __IDXGIFactory2_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87,0xb0, 0x36,0x30,0xfa,0x36,0xa6,0xd0);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("50c83a1c-e072-4c48-87b0-3630fa36a6d0")
+IDXGIFactory2 : public IDXGIFactory1
+{
+    virtual BOOL STDMETHODCALLTYPE IsWindowedStereoEnabled(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd(
+        IUnknown *device,
+        HWND window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSwapChainForCoreWindow(
+        IUnknown *device,
+        IUnknown *window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetSharedResourceAdapterLuid(
+        HANDLE resource,
+        LUID *luid) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterStereoStatusWindow(
+        HWND window,
+        UINT msg,
+        DWORD *cookie) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterStereoStatusEvent(
+        HANDLE event,
+        DWORD *cookie) = 0;
+
+    virtual void STDMETHODCALLTYPE UnregisterStereoStatus(
+        DWORD cookie) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusWindow(
+        HWND window,
+        UINT msg,
+        DWORD *cookie) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusEvent(
+        HANDLE event,
+        DWORD *cookie) = 0;
+
+    virtual void STDMETHODCALLTYPE UnregisterOcclusionStatus(
+        DWORD cookie) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CreateSwapChainForComposition(
+        IUnknown *device,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87,0xb0, 0x36,0x30,0xfa,0x36,0xa6,0xd0)
+#endif
+#else
+typedef struct IDXGIFactory2Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIFactory2 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIFactory2 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIFactory2 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIFactory2 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIFactory2 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIFactory2 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIFactory2 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIFactory methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters)(
+        IDXGIFactory2 *This,
+        UINT adapter_idx,
+        IDXGIAdapter **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *MakeWindowAssociation)(
+        IDXGIFactory2 *This,
+        HWND hwnd,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetWindowAssociation)(
+        IDXGIFactory2 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChain)(
+        IDXGIFactory2 *This,
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSoftwareAdapter)(
+        IDXGIFactory2 *This,
+        HMODULE hmodule,
+        IDXGIAdapter **adapter);
+
+    /*** IDXGIFactory1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters1)(
+        IDXGIFactory2 *This,
+        UINT adapter_idx,
+        IDXGIAdapter1 **adpter);
+
+    BOOL (STDMETHODCALLTYPE *IsCurrent)(
+        IDXGIFactory2 *This);
+
+    /*** IDXGIFactory2 methods ***/
+    BOOL (STDMETHODCALLTYPE *IsWindowedStereoEnabled)(
+        IDXGIFactory2 *This);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForHwnd)(
+        IDXGIFactory2 *This,
+        IUnknown *device,
+        HWND window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForCoreWindow)(
+        IDXGIFactory2 *This,
+        IUnknown *device,
+        IUnknown *window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *GetSharedResourceAdapterLuid)(
+        IDXGIFactory2 *This,
+        HANDLE resource,
+        LUID *luid);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusWindow)(
+        IDXGIFactory2 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusEvent)(
+        IDXGIFactory2 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterStereoStatus)(
+        IDXGIFactory2 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusWindow)(
+        IDXGIFactory2 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusEvent)(
+        IDXGIFactory2 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterOcclusionStatus)(
+        IDXGIFactory2 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForComposition)(
+        IDXGIFactory2 *This,
+        IUnknown *device,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    END_INTERFACE
+} IDXGIFactory2Vtbl;
+
+interface IDXGIFactory2 {
+    CONST_VTBL IDXGIFactory2Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIFactory2_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIFactory2_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIFactory2_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIFactory2_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIFactory2_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIFactory2_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIFactory2_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIFactory methods ***/
+#define IDXGIFactory2_EnumAdapters(This,adapter_idx,adapter) (This)->lpVtbl->EnumAdapters(This,adapter_idx,adapter)
+#define IDXGIFactory2_MakeWindowAssociation(This,hwnd,flags) (This)->lpVtbl->MakeWindowAssociation(This,hwnd,flags)
+#define IDXGIFactory2_GetWindowAssociation(This,hwnd) (This)->lpVtbl->GetWindowAssociation(This,hwnd)
+#define IDXGIFactory2_CreateSwapChain(This,device,desc,swapchain) (This)->lpVtbl->CreateSwapChain(This,device,desc,swapchain)
+#define IDXGIFactory2_CreateSoftwareAdapter(This,hmodule,adapter) (This)->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter)
+/*** IDXGIFactory1 methods ***/
+#define IDXGIFactory2_EnumAdapters1(This,adapter_idx,adpter) (This)->lpVtbl->EnumAdapters1(This,adapter_idx,adpter)
+#define IDXGIFactory2_IsCurrent(This) (This)->lpVtbl->IsCurrent(This)
+/*** IDXGIFactory2 methods ***/
+#define IDXGIFactory2_IsWindowedStereoEnabled(This) (This)->lpVtbl->IsWindowedStereoEnabled(This)
+#define IDXGIFactory2_CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain)
+#define IDXGIFactory2_CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain)
+#define IDXGIFactory2_GetSharedResourceAdapterLuid(This,resource,luid) (This)->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid)
+#define IDXGIFactory2_RegisterStereoStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory2_RegisterStereoStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterStereoStatusEvent(This,event,cookie)
+#define IDXGIFactory2_UnregisterStereoStatus(This,cookie) (This)->lpVtbl->UnregisterStereoStatus(This,cookie)
+#define IDXGIFactory2_RegisterOcclusionStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory2_RegisterOcclusionStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie)
+#define IDXGIFactory2_UnregisterOcclusionStatus(This,cookie) (This)->lpVtbl->UnregisterOcclusionStatus(This,cookie)
+#define IDXGIFactory2_CreateSwapChainForComposition(This,device,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIFactory2_QueryInterface(IDXGIFactory2* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIFactory2_AddRef(IDXGIFactory2* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIFactory2_Release(IDXGIFactory2* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIFactory2_SetPrivateData(IDXGIFactory2* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_GetPrivateDataInterface(IDXGIFactory2* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_GetPrivateData(IDXGIFactory2* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_GetParent(IDXGIFactory2* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIFactory methods ***/
+static FORCEINLINE HRESULT IDXGIFactory2_EnumAdapters(IDXGIFactory2* This,UINT adapter_idx,IDXGIAdapter **adapter) {
+    return This->lpVtbl->EnumAdapters(This,adapter_idx,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_MakeWindowAssociation(IDXGIFactory2* This,HWND hwnd,UINT flags) {
+    return This->lpVtbl->MakeWindowAssociation(This,hwnd,flags);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_GetWindowAssociation(IDXGIFactory2* This,HWND *hwnd) {
+    return This->lpVtbl->GetWindowAssociation(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_CreateSwapChain(IDXGIFactory2* This,IUnknown *device,DXGI_SWAP_CHAIN_DESC *desc,IDXGISwapChain **swapchain) {
+    return This->lpVtbl->CreateSwapChain(This,device,desc,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_CreateSoftwareAdapter(IDXGIFactory2* This,HMODULE hmodule,IDXGIAdapter **adapter) {
+    return This->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter);
+}
+/*** IDXGIFactory1 methods ***/
+static FORCEINLINE HRESULT IDXGIFactory2_EnumAdapters1(IDXGIFactory2* This,UINT adapter_idx,IDXGIAdapter1 **adpter) {
+    return This->lpVtbl->EnumAdapters1(This,adapter_idx,adpter);
+}
+static FORCEINLINE BOOL IDXGIFactory2_IsCurrent(IDXGIFactory2* This) {
+    return This->lpVtbl->IsCurrent(This);
+}
+/*** IDXGIFactory2 methods ***/
+static FORCEINLINE BOOL IDXGIFactory2_IsWindowedStereoEnabled(IDXGIFactory2* This) {
+    return This->lpVtbl->IsWindowedStereoEnabled(This);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_CreateSwapChainForHwnd(IDXGIFactory2* This,IUnknown *device,HWND window,const DXGI_SWAP_CHAIN_DESC1 *desc,const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_CreateSwapChainForCoreWindow(IDXGIFactory2* This,IUnknown *device,IUnknown *window,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_GetSharedResourceAdapterLuid(IDXGIFactory2* This,HANDLE resource,LUID *luid) {
+    return This->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_RegisterStereoStatusWindow(IDXGIFactory2* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_RegisterStereoStatusEvent(IDXGIFactory2* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory2_UnregisterStereoStatus(IDXGIFactory2* This,DWORD cookie) {
+    This->lpVtbl->UnregisterStereoStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_RegisterOcclusionStatusWindow(IDXGIFactory2* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_RegisterOcclusionStatusEvent(IDXGIFactory2* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory2_UnregisterOcclusionStatus(IDXGIFactory2* This,DWORD cookie) {
+    This->lpVtbl->UnregisterOcclusionStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory2_CreateSwapChainForComposition(IDXGIFactory2* This,IUnknown *device,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIFactory2_INTERFACE_DEFINED__ */
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgi1_2_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_2.idl b/dlls/vkd3d/include/vkd3d_dxgi1_2.idl
new file mode 100644
index 00000000000..e7f951ac917
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_2.idl
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_dxgi.idl";
+
+typedef enum DXGI_SCALING
+{
+    DXGI_SCALING_STRETCH              = 0x0,
+    DXGI_SCALING_NONE                 = 0x1,
+    DXGI_SCALING_ASPECT_RATIO_STRETCH = 0x2,
+    DXGI_SCALING_FORCE_DWORD          = 0xffffffff,
+} DXGI_SCALING;
+
+typedef enum DXGI_ALPHA_MODE
+{
+    DXGI_ALPHA_MODE_UNSPECIFIED   = 0x0,
+    DXGI_ALPHA_MODE_PREMULTIPLIED = 0x1,
+    DXGI_ALPHA_MODE_STRAIGHT      = 0x2,
+    DXGI_ALPHA_MODE_IGNORE        = 0x3,
+    DXGI_ALPHA_MODE_FORCE_DWORD   = 0xffffffff,
+} DXGI_ALPHA_MODE;
+
+typedef struct DXGI_SWAP_CHAIN_DESC1
+{
+    UINT Width;
+    UINT Height;
+    DXGI_FORMAT Format;
+    BOOL Stereo;
+    DXGI_SAMPLE_DESC SampleDesc;
+    DXGI_USAGE BufferUsage;
+    UINT BufferCount;
+    DXGI_SCALING Scaling;
+    DXGI_SWAP_EFFECT SwapEffect;
+    DXGI_ALPHA_MODE AlphaMode;
+    UINT Flags;
+} DXGI_SWAP_CHAIN_DESC1;
+
+typedef struct DXGI_SWAP_CHAIN_FULLSCREEN_DESC DXGI_SWAP_CHAIN_FULLSCREEN_DESC;
+typedef struct DXGI_PRESENT_PARAMETERS DXGI_PRESENT_PARAMETERS;
+
+[
+    local,
+    object,
+    uuid(790a45f7-0d42-4876-983a-0a55cfe6f4aa),
+    pointer_default(unique)
+]
+interface IDXGISwapChain1 : IDXGISwapChain
+{
+    HRESULT GetDesc1(DXGI_SWAP_CHAIN_DESC1 *desc);
+    HRESULT GetFullscreenDesc(DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc);
+    HRESULT GetHwnd(HWND *hwnd);
+    HRESULT GetCoreWindow(REFIID riid, void **object);
+    HRESULT Present1(UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *parameters);
+    BOOL IsTemporaryMonoSupported();
+    HRESULT GetRestrictToOutput(IDXGIOutput **output);
+    HRESULT SetBackgroundColor(const DXGI_RGBA *color);
+    HRESULT GetBackgroundColor(DXGI_RGBA *color);
+    HRESULT SetRotation(DXGI_MODE_ROTATION rotation);
+    HRESULT GetRotation(DXGI_MODE_ROTATION *rotation);
+}
+
+[
+    local,
+    object,
+    uuid(50c83a1c-e072-4c48-87b0-3630fa36a6d0),
+    pointer_default(unique)
+]
+interface IDXGIFactory2 : IDXGIFactory1
+{
+    BOOL IsWindowedStereoEnabled();
+    HRESULT CreateSwapChainForHwnd(IUnknown *device, HWND window, const DXGI_SWAP_CHAIN_DESC1 *desc,
+            const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGIOutput *output, IDXGISwapChain1 **swapchain);
+    HRESULT CreateSwapChainForCoreWindow(IUnknown *device, IUnknown *window, const DXGI_SWAP_CHAIN_DESC1 *desc,
+            IDXGIOutput *output, IDXGISwapChain1 **swapchain);
+    HRESULT GetSharedResourceAdapterLuid(HANDLE resource, LUID *luid);
+    HRESULT RegisterStereoStatusWindow(HWND window, UINT msg, DWORD *cookie);
+    HRESULT RegisterStereoStatusEvent(HANDLE event, DWORD *cookie);
+    void UnregisterStereoStatus(DWORD cookie);
+    HRESULT RegisterOcclusionStatusWindow(HWND window, UINT msg, DWORD *cookie);
+    HRESULT RegisterOcclusionStatusEvent(HANDLE event, DWORD *cookie);
+    void UnregisterOcclusionStatus(DWORD cookie);
+    HRESULT CreateSwapChainForComposition(IUnknown *device, const DXGI_SWAP_CHAIN_DESC1 *desc,
+            IDXGIOutput *output, IDXGISwapChain1 **swapchain);
+}
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_3.h b/dlls/vkd3d/include/vkd3d_dxgi1_3.h
new file mode 100644
index 00000000000..4dfc91df35d
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_3.h
@@ -0,0 +1,732 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgi1_3.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgi1_3_h__
+#define __vkd3d_dxgi1_3_h__
+
+/* Forward declarations */
+
+#ifndef __IDXGISwapChain2_FWD_DEFINED__
+#define __IDXGISwapChain2_FWD_DEFINED__
+typedef interface IDXGISwapChain2 IDXGISwapChain2;
+#ifdef __cplusplus
+interface IDXGISwapChain2;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIFactory3_FWD_DEFINED__
+#define __IDXGIFactory3_FWD_DEFINED__
+typedef interface IDXGIFactory3 IDXGIFactory3;
+#ifdef __cplusplus
+interface IDXGIFactory3;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_dxgi1_2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DXGI_MATRIX_3X2_F DXGI_MATRIX_3X2_F;
+/*****************************************************************************
+ * IDXGISwapChain2 interface
+ */
+#ifndef __IDXGISwapChain2_INTERFACE_DEFINED__
+#define __IDXGISwapChain2_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGISwapChain2, 0xa8be2ac4, 0x199f, 0x4946, 0xb3,0x31, 0x79,0x59,0x9f,0xb9,0x8d,0xe7);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("a8be2ac4-199f-4946-b331-79599fb98de7")
+IDXGISwapChain2 : public IDXGISwapChain1
+{
+    virtual HRESULT STDMETHODCALLTYPE SetSourceSize(
+        UINT width,
+        UINT height) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetSourceSize(
+        UINT *width,
+        UINT *height) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(
+        UINT latency) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(
+        UINT *latency) = 0;
+
+    virtual HANDLE STDMETHODCALLTYPE GetFrameLatencyWaitableObject(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetMatrixTransform(
+        const DXGI_MATRIX_3X2_F *matrix) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE GetMatrixTransform(
+        DXGI_MATRIX_3X2_F *matrix) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGISwapChain2, 0xa8be2ac4, 0x199f, 0x4946, 0xb3,0x31, 0x79,0x59,0x9f,0xb9,0x8d,0xe7)
+#endif
+#else
+typedef struct IDXGISwapChain2Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGISwapChain2 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGISwapChain2 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGISwapChain2 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGISwapChain2 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGISwapChain2 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGISwapChain2 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGISwapChain2 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIDeviceSubObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        IDXGISwapChain2 *This,
+        REFIID riid,
+        void **device);
+
+    /*** IDXGISwapChain methods ***/
+    HRESULT (STDMETHODCALLTYPE *Present)(
+        IDXGISwapChain2 *This,
+        UINT sync_interval,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetBuffer)(
+        IDXGISwapChain2 *This,
+        UINT buffer_idx,
+        REFIID riid,
+        void **surface);
+
+    HRESULT (STDMETHODCALLTYPE *SetFullscreenState)(
+        IDXGISwapChain2 *This,
+        BOOL fullscreen,
+        IDXGIOutput *target);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenState)(
+        IDXGISwapChain2 *This,
+        BOOL *fullscreen,
+        IDXGIOutput **target);
+
+    HRESULT (STDMETHODCALLTYPE *GetDesc)(
+        IDXGISwapChain2 *This,
+        DXGI_SWAP_CHAIN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeBuffers)(
+        IDXGISwapChain2 *This,
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeTarget)(
+        IDXGISwapChain2 *This,
+        const DXGI_MODE_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetContainingOutput)(
+        IDXGISwapChain2 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *GetFrameStatistics)(
+        IDXGISwapChain2 *This,
+        DXGI_FRAME_STATISTICS *stats);
+
+    HRESULT (STDMETHODCALLTYPE *GetLastPresentCount)(
+        IDXGISwapChain2 *This,
+        UINT *last_present_count);
+
+    /*** IDXGISwapChain1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDesc1)(
+        IDXGISwapChain2 *This,
+        DXGI_SWAP_CHAIN_DESC1 *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenDesc)(
+        IDXGISwapChain2 *This,
+        DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetHwnd)(
+        IDXGISwapChain2 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *GetCoreWindow)(
+        IDXGISwapChain2 *This,
+        REFIID riid,
+        void **object);
+
+    HRESULT (STDMETHODCALLTYPE *Present1)(
+        IDXGISwapChain2 *This,
+        UINT sync_interval,
+        UINT flags,
+        const DXGI_PRESENT_PARAMETERS *parameters);
+
+    BOOL (STDMETHODCALLTYPE *IsTemporaryMonoSupported)(
+        IDXGISwapChain2 *This);
+
+    HRESULT (STDMETHODCALLTYPE *GetRestrictToOutput)(
+        IDXGISwapChain2 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *SetBackgroundColor)(
+        IDXGISwapChain2 *This,
+        const DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *GetBackgroundColor)(
+        IDXGISwapChain2 *This,
+        DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *SetRotation)(
+        IDXGISwapChain2 *This,
+        DXGI_MODE_ROTATION rotation);
+
+    HRESULT (STDMETHODCALLTYPE *GetRotation)(
+        IDXGISwapChain2 *This,
+        DXGI_MODE_ROTATION *rotation);
+
+    /*** IDXGISwapChain2 methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetSourceSize)(
+        IDXGISwapChain2 *This,
+        UINT width,
+        UINT height);
+
+    HRESULT (STDMETHODCALLTYPE *GetSourceSize)(
+        IDXGISwapChain2 *This,
+        UINT *width,
+        UINT *height);
+
+    HRESULT (STDMETHODCALLTYPE *SetMaximumFrameLatency)(
+        IDXGISwapChain2 *This,
+        UINT latency);
+
+    HRESULT (STDMETHODCALLTYPE *GetMaximumFrameLatency)(
+        IDXGISwapChain2 *This,
+        UINT *latency);
+
+    HANDLE (STDMETHODCALLTYPE *GetFrameLatencyWaitableObject)(
+        IDXGISwapChain2 *This);
+
+    HRESULT (STDMETHODCALLTYPE *SetMatrixTransform)(
+        IDXGISwapChain2 *This,
+        const DXGI_MATRIX_3X2_F *matrix);
+
+    HRESULT (STDMETHODCALLTYPE *GetMatrixTransform)(
+        IDXGISwapChain2 *This,
+        DXGI_MATRIX_3X2_F *matrix);
+
+    END_INTERFACE
+} IDXGISwapChain2Vtbl;
+
+interface IDXGISwapChain2 {
+    CONST_VTBL IDXGISwapChain2Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGISwapChain2_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGISwapChain2_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGISwapChain2_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGISwapChain2_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain2_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGISwapChain2_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain2_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIDeviceSubObject methods ***/
+#define IDXGISwapChain2_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** IDXGISwapChain methods ***/
+#define IDXGISwapChain2_Present(This,sync_interval,flags) (This)->lpVtbl->Present(This,sync_interval,flags)
+#define IDXGISwapChain2_GetBuffer(This,buffer_idx,riid,surface) (This)->lpVtbl->GetBuffer(This,buffer_idx,riid,surface)
+#define IDXGISwapChain2_SetFullscreenState(This,fullscreen,target) (This)->lpVtbl->SetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain2_GetFullscreenState(This,fullscreen,target) (This)->lpVtbl->GetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain2_GetDesc(This,desc) (This)->lpVtbl->GetDesc(This,desc)
+#define IDXGISwapChain2_ResizeBuffers(This,buffer_count,width,height,format,flags) (This)->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags)
+#define IDXGISwapChain2_ResizeTarget(This,desc) (This)->lpVtbl->ResizeTarget(This,desc)
+#define IDXGISwapChain2_GetContainingOutput(This,output) (This)->lpVtbl->GetContainingOutput(This,output)
+#define IDXGISwapChain2_GetFrameStatistics(This,stats) (This)->lpVtbl->GetFrameStatistics(This,stats)
+#define IDXGISwapChain2_GetLastPresentCount(This,last_present_count) (This)->lpVtbl->GetLastPresentCount(This,last_present_count)
+/*** IDXGISwapChain1 methods ***/
+#define IDXGISwapChain2_GetDesc1(This,desc) (This)->lpVtbl->GetDesc1(This,desc)
+#define IDXGISwapChain2_GetFullscreenDesc(This,desc) (This)->lpVtbl->GetFullscreenDesc(This,desc)
+#define IDXGISwapChain2_GetHwnd(This,hwnd) (This)->lpVtbl->GetHwnd(This,hwnd)
+#define IDXGISwapChain2_GetCoreWindow(This,riid,object) (This)->lpVtbl->GetCoreWindow(This,riid,object)
+#define IDXGISwapChain2_Present1(This,sync_interval,flags,parameters) (This)->lpVtbl->Present1(This,sync_interval,flags,parameters)
+#define IDXGISwapChain2_IsTemporaryMonoSupported(This) (This)->lpVtbl->IsTemporaryMonoSupported(This)
+#define IDXGISwapChain2_GetRestrictToOutput(This,output) (This)->lpVtbl->GetRestrictToOutput(This,output)
+#define IDXGISwapChain2_SetBackgroundColor(This,color) (This)->lpVtbl->SetBackgroundColor(This,color)
+#define IDXGISwapChain2_GetBackgroundColor(This,color) (This)->lpVtbl->GetBackgroundColor(This,color)
+#define IDXGISwapChain2_SetRotation(This,rotation) (This)->lpVtbl->SetRotation(This,rotation)
+#define IDXGISwapChain2_GetRotation(This,rotation) (This)->lpVtbl->GetRotation(This,rotation)
+/*** IDXGISwapChain2 methods ***/
+#define IDXGISwapChain2_SetSourceSize(This,width,height) (This)->lpVtbl->SetSourceSize(This,width,height)
+#define IDXGISwapChain2_GetSourceSize(This,width,height) (This)->lpVtbl->GetSourceSize(This,width,height)
+#define IDXGISwapChain2_SetMaximumFrameLatency(This,latency) (This)->lpVtbl->SetMaximumFrameLatency(This,latency)
+#define IDXGISwapChain2_GetMaximumFrameLatency(This,latency) (This)->lpVtbl->GetMaximumFrameLatency(This,latency)
+#define IDXGISwapChain2_GetFrameLatencyWaitableObject(This) (This)->lpVtbl->GetFrameLatencyWaitableObject(This)
+#define IDXGISwapChain2_SetMatrixTransform(This,matrix) (This)->lpVtbl->SetMatrixTransform(This,matrix)
+#define IDXGISwapChain2_GetMatrixTransform(This,matrix) (This)->lpVtbl->GetMatrixTransform(This,matrix)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_QueryInterface(IDXGISwapChain2* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGISwapChain2_AddRef(IDXGISwapChain2* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGISwapChain2_Release(IDXGISwapChain2* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_SetPrivateData(IDXGISwapChain2* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetPrivateDataInterface(IDXGISwapChain2* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetPrivateData(IDXGISwapChain2* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetParent(IDXGISwapChain2* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIDeviceSubObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_GetDevice(IDXGISwapChain2* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** IDXGISwapChain methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_Present(IDXGISwapChain2* This,UINT sync_interval,UINT flags) {
+    return This->lpVtbl->Present(This,sync_interval,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetBuffer(IDXGISwapChain2* This,UINT buffer_idx,REFIID riid,void **surface) {
+    return This->lpVtbl->GetBuffer(This,buffer_idx,riid,surface);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_SetFullscreenState(IDXGISwapChain2* This,BOOL fullscreen,IDXGIOutput *target) {
+    return This->lpVtbl->SetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetFullscreenState(IDXGISwapChain2* This,BOOL *fullscreen,IDXGIOutput **target) {
+    return This->lpVtbl->GetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetDesc(IDXGISwapChain2* This,DXGI_SWAP_CHAIN_DESC *desc) {
+    return This->lpVtbl->GetDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_ResizeBuffers(IDXGISwapChain2* This,UINT buffer_count,UINT width,UINT height,DXGI_FORMAT format,UINT flags) {
+    return This->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_ResizeTarget(IDXGISwapChain2* This,const DXGI_MODE_DESC *desc) {
+    return This->lpVtbl->ResizeTarget(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetContainingOutput(IDXGISwapChain2* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetContainingOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetFrameStatistics(IDXGISwapChain2* This,DXGI_FRAME_STATISTICS *stats) {
+    return This->lpVtbl->GetFrameStatistics(This,stats);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetLastPresentCount(IDXGISwapChain2* This,UINT *last_present_count) {
+    return This->lpVtbl->GetLastPresentCount(This,last_present_count);
+}
+/*** IDXGISwapChain1 methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_GetDesc1(IDXGISwapChain2* This,DXGI_SWAP_CHAIN_DESC1 *desc) {
+    return This->lpVtbl->GetDesc1(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetFullscreenDesc(IDXGISwapChain2* This,DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) {
+    return This->lpVtbl->GetFullscreenDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetHwnd(IDXGISwapChain2* This,HWND *hwnd) {
+    return This->lpVtbl->GetHwnd(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetCoreWindow(IDXGISwapChain2* This,REFIID riid,void **object) {
+    return This->lpVtbl->GetCoreWindow(This,riid,object);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_Present1(IDXGISwapChain2* This,UINT sync_interval,UINT flags,const DXGI_PRESENT_PARAMETERS *parameters) {
+    return This->lpVtbl->Present1(This,sync_interval,flags,parameters);
+}
+static FORCEINLINE BOOL IDXGISwapChain2_IsTemporaryMonoSupported(IDXGISwapChain2* This) {
+    return This->lpVtbl->IsTemporaryMonoSupported(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetRestrictToOutput(IDXGISwapChain2* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetRestrictToOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_SetBackgroundColor(IDXGISwapChain2* This,const DXGI_RGBA *color) {
+    return This->lpVtbl->SetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetBackgroundColor(IDXGISwapChain2* This,DXGI_RGBA *color) {
+    return This->lpVtbl->GetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_SetRotation(IDXGISwapChain2* This,DXGI_MODE_ROTATION rotation) {
+    return This->lpVtbl->SetRotation(This,rotation);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetRotation(IDXGISwapChain2* This,DXGI_MODE_ROTATION *rotation) {
+    return This->lpVtbl->GetRotation(This,rotation);
+}
+/*** IDXGISwapChain2 methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain2_SetSourceSize(IDXGISwapChain2* This,UINT width,UINT height) {
+    return This->lpVtbl->SetSourceSize(This,width,height);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetSourceSize(IDXGISwapChain2* This,UINT *width,UINT *height) {
+    return This->lpVtbl->GetSourceSize(This,width,height);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_SetMaximumFrameLatency(IDXGISwapChain2* This,UINT latency) {
+    return This->lpVtbl->SetMaximumFrameLatency(This,latency);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetMaximumFrameLatency(IDXGISwapChain2* This,UINT *latency) {
+    return This->lpVtbl->GetMaximumFrameLatency(This,latency);
+}
+static FORCEINLINE HANDLE IDXGISwapChain2_GetFrameLatencyWaitableObject(IDXGISwapChain2* This) {
+    return This->lpVtbl->GetFrameLatencyWaitableObject(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_SetMatrixTransform(IDXGISwapChain2* This,const DXGI_MATRIX_3X2_F *matrix) {
+    return This->lpVtbl->SetMatrixTransform(This,matrix);
+}
+static FORCEINLINE HRESULT IDXGISwapChain2_GetMatrixTransform(IDXGISwapChain2* This,DXGI_MATRIX_3X2_F *matrix) {
+    return This->lpVtbl->GetMatrixTransform(This,matrix);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGISwapChain2_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIFactory3 interface
+ */
+#ifndef __IDXGIFactory3_INTERFACE_DEFINED__
+#define __IDXGIFactory3_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIFactory3, 0x25483823, 0xcd46, 0x4c7d, 0x86,0xca, 0x47,0xaa,0x95,0xb8,0x37,0xbd);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("25483823-cd46-4c7d-86ca-47aa95b837bd")
+IDXGIFactory3 : public IDXGIFactory2
+{
+    virtual UINT STDMETHODCALLTYPE GetCreationFlags(
+        ) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIFactory3, 0x25483823, 0xcd46, 0x4c7d, 0x86,0xca, 0x47,0xaa,0x95,0xb8,0x37,0xbd)
+#endif
+#else
+typedef struct IDXGIFactory3Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIFactory3 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIFactory3 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIFactory3 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIFactory3 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIFactory3 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIFactory3 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIFactory3 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIFactory methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters)(
+        IDXGIFactory3 *This,
+        UINT adapter_idx,
+        IDXGIAdapter **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *MakeWindowAssociation)(
+        IDXGIFactory3 *This,
+        HWND hwnd,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetWindowAssociation)(
+        IDXGIFactory3 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChain)(
+        IDXGIFactory3 *This,
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSoftwareAdapter)(
+        IDXGIFactory3 *This,
+        HMODULE hmodule,
+        IDXGIAdapter **adapter);
+
+    /*** IDXGIFactory1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters1)(
+        IDXGIFactory3 *This,
+        UINT adapter_idx,
+        IDXGIAdapter1 **adpter);
+
+    BOOL (STDMETHODCALLTYPE *IsCurrent)(
+        IDXGIFactory3 *This);
+
+    /*** IDXGIFactory2 methods ***/
+    BOOL (STDMETHODCALLTYPE *IsWindowedStereoEnabled)(
+        IDXGIFactory3 *This);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForHwnd)(
+        IDXGIFactory3 *This,
+        IUnknown *device,
+        HWND window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForCoreWindow)(
+        IDXGIFactory3 *This,
+        IUnknown *device,
+        IUnknown *window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *GetSharedResourceAdapterLuid)(
+        IDXGIFactory3 *This,
+        HANDLE resource,
+        LUID *luid);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusWindow)(
+        IDXGIFactory3 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusEvent)(
+        IDXGIFactory3 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterStereoStatus)(
+        IDXGIFactory3 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusWindow)(
+        IDXGIFactory3 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusEvent)(
+        IDXGIFactory3 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterOcclusionStatus)(
+        IDXGIFactory3 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForComposition)(
+        IDXGIFactory3 *This,
+        IUnknown *device,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    /*** IDXGIFactory3 methods ***/
+    UINT (STDMETHODCALLTYPE *GetCreationFlags)(
+        IDXGIFactory3 *This);
+
+    END_INTERFACE
+} IDXGIFactory3Vtbl;
+
+interface IDXGIFactory3 {
+    CONST_VTBL IDXGIFactory3Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIFactory3_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIFactory3_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIFactory3_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIFactory3_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIFactory3_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIFactory3_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIFactory3_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIFactory methods ***/
+#define IDXGIFactory3_EnumAdapters(This,adapter_idx,adapter) (This)->lpVtbl->EnumAdapters(This,adapter_idx,adapter)
+#define IDXGIFactory3_MakeWindowAssociation(This,hwnd,flags) (This)->lpVtbl->MakeWindowAssociation(This,hwnd,flags)
+#define IDXGIFactory3_GetWindowAssociation(This,hwnd) (This)->lpVtbl->GetWindowAssociation(This,hwnd)
+#define IDXGIFactory3_CreateSwapChain(This,device,desc,swapchain) (This)->lpVtbl->CreateSwapChain(This,device,desc,swapchain)
+#define IDXGIFactory3_CreateSoftwareAdapter(This,hmodule,adapter) (This)->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter)
+/*** IDXGIFactory1 methods ***/
+#define IDXGIFactory3_EnumAdapters1(This,adapter_idx,adpter) (This)->lpVtbl->EnumAdapters1(This,adapter_idx,adpter)
+#define IDXGIFactory3_IsCurrent(This) (This)->lpVtbl->IsCurrent(This)
+/*** IDXGIFactory2 methods ***/
+#define IDXGIFactory3_IsWindowedStereoEnabled(This) (This)->lpVtbl->IsWindowedStereoEnabled(This)
+#define IDXGIFactory3_CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain)
+#define IDXGIFactory3_CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain)
+#define IDXGIFactory3_GetSharedResourceAdapterLuid(This,resource,luid) (This)->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid)
+#define IDXGIFactory3_RegisterStereoStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory3_RegisterStereoStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterStereoStatusEvent(This,event,cookie)
+#define IDXGIFactory3_UnregisterStereoStatus(This,cookie) (This)->lpVtbl->UnregisterStereoStatus(This,cookie)
+#define IDXGIFactory3_RegisterOcclusionStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory3_RegisterOcclusionStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie)
+#define IDXGIFactory3_UnregisterOcclusionStatus(This,cookie) (This)->lpVtbl->UnregisterOcclusionStatus(This,cookie)
+#define IDXGIFactory3_CreateSwapChainForComposition(This,device,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain)
+/*** IDXGIFactory3 methods ***/
+#define IDXGIFactory3_GetCreationFlags(This) (This)->lpVtbl->GetCreationFlags(This)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIFactory3_QueryInterface(IDXGIFactory3* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIFactory3_AddRef(IDXGIFactory3* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIFactory3_Release(IDXGIFactory3* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIFactory3_SetPrivateData(IDXGIFactory3* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_GetPrivateDataInterface(IDXGIFactory3* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_GetPrivateData(IDXGIFactory3* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_GetParent(IDXGIFactory3* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIFactory methods ***/
+static FORCEINLINE HRESULT IDXGIFactory3_EnumAdapters(IDXGIFactory3* This,UINT adapter_idx,IDXGIAdapter **adapter) {
+    return This->lpVtbl->EnumAdapters(This,adapter_idx,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_MakeWindowAssociation(IDXGIFactory3* This,HWND hwnd,UINT flags) {
+    return This->lpVtbl->MakeWindowAssociation(This,hwnd,flags);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_GetWindowAssociation(IDXGIFactory3* This,HWND *hwnd) {
+    return This->lpVtbl->GetWindowAssociation(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_CreateSwapChain(IDXGIFactory3* This,IUnknown *device,DXGI_SWAP_CHAIN_DESC *desc,IDXGISwapChain **swapchain) {
+    return This->lpVtbl->CreateSwapChain(This,device,desc,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_CreateSoftwareAdapter(IDXGIFactory3* This,HMODULE hmodule,IDXGIAdapter **adapter) {
+    return This->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter);
+}
+/*** IDXGIFactory1 methods ***/
+static FORCEINLINE HRESULT IDXGIFactory3_EnumAdapters1(IDXGIFactory3* This,UINT adapter_idx,IDXGIAdapter1 **adpter) {
+    return This->lpVtbl->EnumAdapters1(This,adapter_idx,adpter);
+}
+static FORCEINLINE BOOL IDXGIFactory3_IsCurrent(IDXGIFactory3* This) {
+    return This->lpVtbl->IsCurrent(This);
+}
+/*** IDXGIFactory2 methods ***/
+static FORCEINLINE BOOL IDXGIFactory3_IsWindowedStereoEnabled(IDXGIFactory3* This) {
+    return This->lpVtbl->IsWindowedStereoEnabled(This);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_CreateSwapChainForHwnd(IDXGIFactory3* This,IUnknown *device,HWND window,const DXGI_SWAP_CHAIN_DESC1 *desc,const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_CreateSwapChainForCoreWindow(IDXGIFactory3* This,IUnknown *device,IUnknown *window,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_GetSharedResourceAdapterLuid(IDXGIFactory3* This,HANDLE resource,LUID *luid) {
+    return This->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_RegisterStereoStatusWindow(IDXGIFactory3* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_RegisterStereoStatusEvent(IDXGIFactory3* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory3_UnregisterStereoStatus(IDXGIFactory3* This,DWORD cookie) {
+    This->lpVtbl->UnregisterStereoStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_RegisterOcclusionStatusWindow(IDXGIFactory3* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_RegisterOcclusionStatusEvent(IDXGIFactory3* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory3_UnregisterOcclusionStatus(IDXGIFactory3* This,DWORD cookie) {
+    This->lpVtbl->UnregisterOcclusionStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory3_CreateSwapChainForComposition(IDXGIFactory3* This,IUnknown *device,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain);
+}
+/*** IDXGIFactory3 methods ***/
+static FORCEINLINE UINT IDXGIFactory3_GetCreationFlags(IDXGIFactory3* This) {
+    return This->lpVtbl->GetCreationFlags(This);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIFactory3_INTERFACE_DEFINED__ */
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgi1_3_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_3.idl b/dlls/vkd3d/include/vkd3d_dxgi1_3.idl
new file mode 100644
index 00000000000..88ac0a34f70
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_3.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_dxgi1_2.idl";
+
+typedef struct DXGI_MATRIX_3X2_F DXGI_MATRIX_3X2_F;
+
+[
+    local,
+    object,
+    uuid(a8be2ac4-199f-4946-b331-79599fb98de7),
+    pointer_default(unique)
+]
+interface IDXGISwapChain2 : IDXGISwapChain1
+{
+    HRESULT SetSourceSize(UINT width, UINT height);
+    HRESULT GetSourceSize(UINT *width, UINT *height);
+    HRESULT SetMaximumFrameLatency(UINT latency);
+    HRESULT GetMaximumFrameLatency(UINT *latency);
+    HANDLE  GetFrameLatencyWaitableObject();
+    HRESULT SetMatrixTransform(const DXGI_MATRIX_3X2_F *matrix);
+    HRESULT GetMatrixTransform(DXGI_MATRIX_3X2_F *matrix);
+}
+
+[
+    local,
+    object,
+    uuid(25483823-cd46-4c7d-86ca-47aa95b837bd),
+    pointer_default(unique)
+]
+interface IDXGIFactory3 : IDXGIFactory2
+{
+    UINT GetCreationFlags();
+}
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_4.h b/dlls/vkd3d/include/vkd3d_dxgi1_4.h
new file mode 100644
index 00000000000..eaa2b94b12f
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_4.h
@@ -0,0 +1,796 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgi1_4.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgi1_4_h__
+#define __vkd3d_dxgi1_4_h__
+
+/* Forward declarations */
+
+#ifndef __IDXGISwapChain3_FWD_DEFINED__
+#define __IDXGISwapChain3_FWD_DEFINED__
+typedef interface IDXGISwapChain3 IDXGISwapChain3;
+#ifdef __cplusplus
+interface IDXGISwapChain3;
+#endif /* __cplusplus */
+#endif
+
+#ifndef __IDXGIFactory4_FWD_DEFINED__
+#define __IDXGIFactory4_FWD_DEFINED__
+typedef interface IDXGIFactory4 IDXGIFactory4;
+#ifdef __cplusplus
+interface IDXGIFactory4;
+#endif /* __cplusplus */
+#endif
+
+/* Headers for imported files */
+
+#include <vkd3d_dxgi1_3.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ * IDXGISwapChain3 interface
+ */
+#ifndef __IDXGISwapChain3_INTERFACE_DEFINED__
+#define __IDXGISwapChain3_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGISwapChain3, 0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("94d99bdb-f1f8-4ab0-b236-7da0170edab1")
+IDXGISwapChain3 : public IDXGISwapChain2
+{
+    virtual UINT STDMETHODCALLTYPE GetCurrentBackBufferIndex(
+        ) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE CheckColorSpaceSupport(
+        DXGI_COLOR_SPACE_TYPE type,
+        UINT *support) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetColorSpace1(
+        DXGI_COLOR_SPACE_TYPE type) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ResizeBuffers1(
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags,
+        const UINT *node_mask,
+        IUnknown *const *present_queue) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGISwapChain3, 0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1)
+#endif
+#else
+typedef struct IDXGISwapChain3Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGISwapChain3 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGISwapChain3 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGISwapChain3 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGISwapChain3 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGISwapChain3 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGISwapChain3 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGISwapChain3 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIDeviceSubObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDevice)(
+        IDXGISwapChain3 *This,
+        REFIID riid,
+        void **device);
+
+    /*** IDXGISwapChain methods ***/
+    HRESULT (STDMETHODCALLTYPE *Present)(
+        IDXGISwapChain3 *This,
+        UINT sync_interval,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetBuffer)(
+        IDXGISwapChain3 *This,
+        UINT buffer_idx,
+        REFIID riid,
+        void **surface);
+
+    HRESULT (STDMETHODCALLTYPE *SetFullscreenState)(
+        IDXGISwapChain3 *This,
+        BOOL fullscreen,
+        IDXGIOutput *target);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenState)(
+        IDXGISwapChain3 *This,
+        BOOL *fullscreen,
+        IDXGIOutput **target);
+
+    HRESULT (STDMETHODCALLTYPE *GetDesc)(
+        IDXGISwapChain3 *This,
+        DXGI_SWAP_CHAIN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeBuffers)(
+        IDXGISwapChain3 *This,
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeTarget)(
+        IDXGISwapChain3 *This,
+        const DXGI_MODE_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetContainingOutput)(
+        IDXGISwapChain3 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *GetFrameStatistics)(
+        IDXGISwapChain3 *This,
+        DXGI_FRAME_STATISTICS *stats);
+
+    HRESULT (STDMETHODCALLTYPE *GetLastPresentCount)(
+        IDXGISwapChain3 *This,
+        UINT *last_present_count);
+
+    /*** IDXGISwapChain1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *GetDesc1)(
+        IDXGISwapChain3 *This,
+        DXGI_SWAP_CHAIN_DESC1 *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetFullscreenDesc)(
+        IDXGISwapChain3 *This,
+        DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc);
+
+    HRESULT (STDMETHODCALLTYPE *GetHwnd)(
+        IDXGISwapChain3 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *GetCoreWindow)(
+        IDXGISwapChain3 *This,
+        REFIID riid,
+        void **object);
+
+    HRESULT (STDMETHODCALLTYPE *Present1)(
+        IDXGISwapChain3 *This,
+        UINT sync_interval,
+        UINT flags,
+        const DXGI_PRESENT_PARAMETERS *parameters);
+
+    BOOL (STDMETHODCALLTYPE *IsTemporaryMonoSupported)(
+        IDXGISwapChain3 *This);
+
+    HRESULT (STDMETHODCALLTYPE *GetRestrictToOutput)(
+        IDXGISwapChain3 *This,
+        IDXGIOutput **output);
+
+    HRESULT (STDMETHODCALLTYPE *SetBackgroundColor)(
+        IDXGISwapChain3 *This,
+        const DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *GetBackgroundColor)(
+        IDXGISwapChain3 *This,
+        DXGI_RGBA *color);
+
+    HRESULT (STDMETHODCALLTYPE *SetRotation)(
+        IDXGISwapChain3 *This,
+        DXGI_MODE_ROTATION rotation);
+
+    HRESULT (STDMETHODCALLTYPE *GetRotation)(
+        IDXGISwapChain3 *This,
+        DXGI_MODE_ROTATION *rotation);
+
+    /*** IDXGISwapChain2 methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetSourceSize)(
+        IDXGISwapChain3 *This,
+        UINT width,
+        UINT height);
+
+    HRESULT (STDMETHODCALLTYPE *GetSourceSize)(
+        IDXGISwapChain3 *This,
+        UINT *width,
+        UINT *height);
+
+    HRESULT (STDMETHODCALLTYPE *SetMaximumFrameLatency)(
+        IDXGISwapChain3 *This,
+        UINT latency);
+
+    HRESULT (STDMETHODCALLTYPE *GetMaximumFrameLatency)(
+        IDXGISwapChain3 *This,
+        UINT *latency);
+
+    HANDLE (STDMETHODCALLTYPE *GetFrameLatencyWaitableObject)(
+        IDXGISwapChain3 *This);
+
+    HRESULT (STDMETHODCALLTYPE *SetMatrixTransform)(
+        IDXGISwapChain3 *This,
+        const DXGI_MATRIX_3X2_F *matrix);
+
+    HRESULT (STDMETHODCALLTYPE *GetMatrixTransform)(
+        IDXGISwapChain3 *This,
+        DXGI_MATRIX_3X2_F *matrix);
+
+    /*** IDXGISwapChain3 methods ***/
+    UINT (STDMETHODCALLTYPE *GetCurrentBackBufferIndex)(
+        IDXGISwapChain3 *This);
+
+    HRESULT (STDMETHODCALLTYPE *CheckColorSpaceSupport)(
+        IDXGISwapChain3 *This,
+        DXGI_COLOR_SPACE_TYPE type,
+        UINT *support);
+
+    HRESULT (STDMETHODCALLTYPE *SetColorSpace1)(
+        IDXGISwapChain3 *This,
+        DXGI_COLOR_SPACE_TYPE type);
+
+    HRESULT (STDMETHODCALLTYPE *ResizeBuffers1)(
+        IDXGISwapChain3 *This,
+        UINT buffer_count,
+        UINT width,
+        UINT height,
+        DXGI_FORMAT format,
+        UINT flags,
+        const UINT *node_mask,
+        IUnknown *const *present_queue);
+
+    END_INTERFACE
+} IDXGISwapChain3Vtbl;
+
+interface IDXGISwapChain3 {
+    CONST_VTBL IDXGISwapChain3Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGISwapChain3_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGISwapChain3_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGISwapChain3_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGISwapChain3_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain3_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGISwapChain3_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGISwapChain3_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIDeviceSubObject methods ***/
+#define IDXGISwapChain3_GetDevice(This,riid,device) (This)->lpVtbl->GetDevice(This,riid,device)
+/*** IDXGISwapChain methods ***/
+#define IDXGISwapChain3_Present(This,sync_interval,flags) (This)->lpVtbl->Present(This,sync_interval,flags)
+#define IDXGISwapChain3_GetBuffer(This,buffer_idx,riid,surface) (This)->lpVtbl->GetBuffer(This,buffer_idx,riid,surface)
+#define IDXGISwapChain3_SetFullscreenState(This,fullscreen,target) (This)->lpVtbl->SetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain3_GetFullscreenState(This,fullscreen,target) (This)->lpVtbl->GetFullscreenState(This,fullscreen,target)
+#define IDXGISwapChain3_GetDesc(This,desc) (This)->lpVtbl->GetDesc(This,desc)
+#define IDXGISwapChain3_ResizeBuffers(This,buffer_count,width,height,format,flags) (This)->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags)
+#define IDXGISwapChain3_ResizeTarget(This,desc) (This)->lpVtbl->ResizeTarget(This,desc)
+#define IDXGISwapChain3_GetContainingOutput(This,output) (This)->lpVtbl->GetContainingOutput(This,output)
+#define IDXGISwapChain3_GetFrameStatistics(This,stats) (This)->lpVtbl->GetFrameStatistics(This,stats)
+#define IDXGISwapChain3_GetLastPresentCount(This,last_present_count) (This)->lpVtbl->GetLastPresentCount(This,last_present_count)
+/*** IDXGISwapChain1 methods ***/
+#define IDXGISwapChain3_GetDesc1(This,desc) (This)->lpVtbl->GetDesc1(This,desc)
+#define IDXGISwapChain3_GetFullscreenDesc(This,desc) (This)->lpVtbl->GetFullscreenDesc(This,desc)
+#define IDXGISwapChain3_GetHwnd(This,hwnd) (This)->lpVtbl->GetHwnd(This,hwnd)
+#define IDXGISwapChain3_GetCoreWindow(This,riid,object) (This)->lpVtbl->GetCoreWindow(This,riid,object)
+#define IDXGISwapChain3_Present1(This,sync_interval,flags,parameters) (This)->lpVtbl->Present1(This,sync_interval,flags,parameters)
+#define IDXGISwapChain3_IsTemporaryMonoSupported(This) (This)->lpVtbl->IsTemporaryMonoSupported(This)
+#define IDXGISwapChain3_GetRestrictToOutput(This,output) (This)->lpVtbl->GetRestrictToOutput(This,output)
+#define IDXGISwapChain3_SetBackgroundColor(This,color) (This)->lpVtbl->SetBackgroundColor(This,color)
+#define IDXGISwapChain3_GetBackgroundColor(This,color) (This)->lpVtbl->GetBackgroundColor(This,color)
+#define IDXGISwapChain3_SetRotation(This,rotation) (This)->lpVtbl->SetRotation(This,rotation)
+#define IDXGISwapChain3_GetRotation(This,rotation) (This)->lpVtbl->GetRotation(This,rotation)
+/*** IDXGISwapChain2 methods ***/
+#define IDXGISwapChain3_SetSourceSize(This,width,height) (This)->lpVtbl->SetSourceSize(This,width,height)
+#define IDXGISwapChain3_GetSourceSize(This,width,height) (This)->lpVtbl->GetSourceSize(This,width,height)
+#define IDXGISwapChain3_SetMaximumFrameLatency(This,latency) (This)->lpVtbl->SetMaximumFrameLatency(This,latency)
+#define IDXGISwapChain3_GetMaximumFrameLatency(This,latency) (This)->lpVtbl->GetMaximumFrameLatency(This,latency)
+#define IDXGISwapChain3_GetFrameLatencyWaitableObject(This) (This)->lpVtbl->GetFrameLatencyWaitableObject(This)
+#define IDXGISwapChain3_SetMatrixTransform(This,matrix) (This)->lpVtbl->SetMatrixTransform(This,matrix)
+#define IDXGISwapChain3_GetMatrixTransform(This,matrix) (This)->lpVtbl->GetMatrixTransform(This,matrix)
+/*** IDXGISwapChain3 methods ***/
+#define IDXGISwapChain3_GetCurrentBackBufferIndex(This) (This)->lpVtbl->GetCurrentBackBufferIndex(This)
+#define IDXGISwapChain3_CheckColorSpaceSupport(This,type,support) (This)->lpVtbl->CheckColorSpaceSupport(This,type,support)
+#define IDXGISwapChain3_SetColorSpace1(This,type) (This)->lpVtbl->SetColorSpace1(This,type)
+#define IDXGISwapChain3_ResizeBuffers1(This,buffer_count,width,height,format,flags,node_mask,present_queue) (This)->lpVtbl->ResizeBuffers1(This,buffer_count,width,height,format,flags,node_mask,present_queue)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_QueryInterface(IDXGISwapChain3* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGISwapChain3_AddRef(IDXGISwapChain3* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGISwapChain3_Release(IDXGISwapChain3* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_SetPrivateData(IDXGISwapChain3* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetPrivateDataInterface(IDXGISwapChain3* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetPrivateData(IDXGISwapChain3* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetParent(IDXGISwapChain3* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIDeviceSubObject methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_GetDevice(IDXGISwapChain3* This,REFIID riid,void **device) {
+    return This->lpVtbl->GetDevice(This,riid,device);
+}
+/*** IDXGISwapChain methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_Present(IDXGISwapChain3* This,UINT sync_interval,UINT flags) {
+    return This->lpVtbl->Present(This,sync_interval,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetBuffer(IDXGISwapChain3* This,UINT buffer_idx,REFIID riid,void **surface) {
+    return This->lpVtbl->GetBuffer(This,buffer_idx,riid,surface);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetFullscreenState(IDXGISwapChain3* This,BOOL fullscreen,IDXGIOutput *target) {
+    return This->lpVtbl->SetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetFullscreenState(IDXGISwapChain3* This,BOOL *fullscreen,IDXGIOutput **target) {
+    return This->lpVtbl->GetFullscreenState(This,fullscreen,target);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetDesc(IDXGISwapChain3* This,DXGI_SWAP_CHAIN_DESC *desc) {
+    return This->lpVtbl->GetDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_ResizeBuffers(IDXGISwapChain3* This,UINT buffer_count,UINT width,UINT height,DXGI_FORMAT format,UINT flags) {
+    return This->lpVtbl->ResizeBuffers(This,buffer_count,width,height,format,flags);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_ResizeTarget(IDXGISwapChain3* This,const DXGI_MODE_DESC *desc) {
+    return This->lpVtbl->ResizeTarget(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetContainingOutput(IDXGISwapChain3* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetContainingOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetFrameStatistics(IDXGISwapChain3* This,DXGI_FRAME_STATISTICS *stats) {
+    return This->lpVtbl->GetFrameStatistics(This,stats);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetLastPresentCount(IDXGISwapChain3* This,UINT *last_present_count) {
+    return This->lpVtbl->GetLastPresentCount(This,last_present_count);
+}
+/*** IDXGISwapChain1 methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_GetDesc1(IDXGISwapChain3* This,DXGI_SWAP_CHAIN_DESC1 *desc) {
+    return This->lpVtbl->GetDesc1(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetFullscreenDesc(IDXGISwapChain3* This,DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) {
+    return This->lpVtbl->GetFullscreenDesc(This,desc);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetHwnd(IDXGISwapChain3* This,HWND *hwnd) {
+    return This->lpVtbl->GetHwnd(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetCoreWindow(IDXGISwapChain3* This,REFIID riid,void **object) {
+    return This->lpVtbl->GetCoreWindow(This,riid,object);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_Present1(IDXGISwapChain3* This,UINT sync_interval,UINT flags,const DXGI_PRESENT_PARAMETERS *parameters) {
+    return This->lpVtbl->Present1(This,sync_interval,flags,parameters);
+}
+static FORCEINLINE BOOL IDXGISwapChain3_IsTemporaryMonoSupported(IDXGISwapChain3* This) {
+    return This->lpVtbl->IsTemporaryMonoSupported(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetRestrictToOutput(IDXGISwapChain3* This,IDXGIOutput **output) {
+    return This->lpVtbl->GetRestrictToOutput(This,output);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetBackgroundColor(IDXGISwapChain3* This,const DXGI_RGBA *color) {
+    return This->lpVtbl->SetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetBackgroundColor(IDXGISwapChain3* This,DXGI_RGBA *color) {
+    return This->lpVtbl->GetBackgroundColor(This,color);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetRotation(IDXGISwapChain3* This,DXGI_MODE_ROTATION rotation) {
+    return This->lpVtbl->SetRotation(This,rotation);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetRotation(IDXGISwapChain3* This,DXGI_MODE_ROTATION *rotation) {
+    return This->lpVtbl->GetRotation(This,rotation);
+}
+/*** IDXGISwapChain2 methods ***/
+static FORCEINLINE HRESULT IDXGISwapChain3_SetSourceSize(IDXGISwapChain3* This,UINT width,UINT height) {
+    return This->lpVtbl->SetSourceSize(This,width,height);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetSourceSize(IDXGISwapChain3* This,UINT *width,UINT *height) {
+    return This->lpVtbl->GetSourceSize(This,width,height);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetMaximumFrameLatency(IDXGISwapChain3* This,UINT latency) {
+    return This->lpVtbl->SetMaximumFrameLatency(This,latency);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetMaximumFrameLatency(IDXGISwapChain3* This,UINT *latency) {
+    return This->lpVtbl->GetMaximumFrameLatency(This,latency);
+}
+static FORCEINLINE HANDLE IDXGISwapChain3_GetFrameLatencyWaitableObject(IDXGISwapChain3* This) {
+    return This->lpVtbl->GetFrameLatencyWaitableObject(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetMatrixTransform(IDXGISwapChain3* This,const DXGI_MATRIX_3X2_F *matrix) {
+    return This->lpVtbl->SetMatrixTransform(This,matrix);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_GetMatrixTransform(IDXGISwapChain3* This,DXGI_MATRIX_3X2_F *matrix) {
+    return This->lpVtbl->GetMatrixTransform(This,matrix);
+}
+/*** IDXGISwapChain3 methods ***/
+static FORCEINLINE UINT IDXGISwapChain3_GetCurrentBackBufferIndex(IDXGISwapChain3* This) {
+    return This->lpVtbl->GetCurrentBackBufferIndex(This);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_CheckColorSpaceSupport(IDXGISwapChain3* This,DXGI_COLOR_SPACE_TYPE type,UINT *support) {
+    return This->lpVtbl->CheckColorSpaceSupport(This,type,support);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_SetColorSpace1(IDXGISwapChain3* This,DXGI_COLOR_SPACE_TYPE type) {
+    return This->lpVtbl->SetColorSpace1(This,type);
+}
+static FORCEINLINE HRESULT IDXGISwapChain3_ResizeBuffers1(IDXGISwapChain3* This,UINT buffer_count,UINT width,UINT height,DXGI_FORMAT format,UINT flags,const UINT *node_mask,IUnknown *const *present_queue) {
+    return This->lpVtbl->ResizeBuffers1(This,buffer_count,width,height,format,flags,node_mask,present_queue);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGISwapChain3_INTERFACE_DEFINED__ */
+
+/*****************************************************************************
+ * IDXGIFactory4 interface
+ */
+#ifndef __IDXGIFactory4_INTERFACE_DEFINED__
+#define __IDXGIFactory4_INTERFACE_DEFINED__
+
+DEFINE_GUID(IID_IDXGIFactory4, 0x1bc6ea02, 0xef36, 0x464f, 0xbf,0x0c, 0x21,0xca,0x39,0xe5,0x16,0x8a);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("1bc6ea02-ef36-464f-bf0c-21ca39e5168a")
+IDXGIFactory4 : public IDXGIFactory3
+{
+    virtual HRESULT STDMETHODCALLTYPE EnumAdapterByLuid(
+        LUID luid,
+        REFIID iid,
+        void **adapter) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE EnumWarpAdapter(
+        REFIID iid,
+        void **adapter) = 0;
+
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IDXGIFactory4, 0x1bc6ea02, 0xef36, 0x464f, 0xbf,0x0c, 0x21,0xca,0x39,0xe5,0x16,0x8a)
+#endif
+#else
+typedef struct IDXGIFactory4Vtbl {
+    BEGIN_INTERFACE
+
+    /*** IUnknown methods ***/
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+        IDXGIFactory4 *This,
+        REFIID riid,
+        void **object);
+
+    ULONG (STDMETHODCALLTYPE *AddRef)(
+        IDXGIFactory4 *This);
+
+    ULONG (STDMETHODCALLTYPE *Release)(
+        IDXGIFactory4 *This);
+
+    /*** IDXGIObject methods ***/
+    HRESULT (STDMETHODCALLTYPE *SetPrivateData)(
+        IDXGIFactory4 *This,
+        REFGUID name,
+        UINT data_size,
+        const void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateDataInterface)(
+        IDXGIFactory4 *This,
+        REFGUID name,
+        const IUnknown *unknown);
+
+    HRESULT (STDMETHODCALLTYPE *GetPrivateData)(
+        IDXGIFactory4 *This,
+        REFGUID name,
+        UINT *data_size,
+        void *data);
+
+    HRESULT (STDMETHODCALLTYPE *GetParent)(
+        IDXGIFactory4 *This,
+        REFIID riid,
+        void **parent);
+
+    /*** IDXGIFactory methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters)(
+        IDXGIFactory4 *This,
+        UINT adapter_idx,
+        IDXGIAdapter **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *MakeWindowAssociation)(
+        IDXGIFactory4 *This,
+        HWND hwnd,
+        UINT flags);
+
+    HRESULT (STDMETHODCALLTYPE *GetWindowAssociation)(
+        IDXGIFactory4 *This,
+        HWND *hwnd);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChain)(
+        IDXGIFactory4 *This,
+        IUnknown *device,
+        DXGI_SWAP_CHAIN_DESC *desc,
+        IDXGISwapChain **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSoftwareAdapter)(
+        IDXGIFactory4 *This,
+        HMODULE hmodule,
+        IDXGIAdapter **adapter);
+
+    /*** IDXGIFactory1 methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapters1)(
+        IDXGIFactory4 *This,
+        UINT adapter_idx,
+        IDXGIAdapter1 **adpter);
+
+    BOOL (STDMETHODCALLTYPE *IsCurrent)(
+        IDXGIFactory4 *This);
+
+    /*** IDXGIFactory2 methods ***/
+    BOOL (STDMETHODCALLTYPE *IsWindowedStereoEnabled)(
+        IDXGIFactory4 *This);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForHwnd)(
+        IDXGIFactory4 *This,
+        IUnknown *device,
+        HWND window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForCoreWindow)(
+        IDXGIFactory4 *This,
+        IUnknown *device,
+        IUnknown *window,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    HRESULT (STDMETHODCALLTYPE *GetSharedResourceAdapterLuid)(
+        IDXGIFactory4 *This,
+        HANDLE resource,
+        LUID *luid);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusWindow)(
+        IDXGIFactory4 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterStereoStatusEvent)(
+        IDXGIFactory4 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterStereoStatus)(
+        IDXGIFactory4 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusWindow)(
+        IDXGIFactory4 *This,
+        HWND window,
+        UINT msg,
+        DWORD *cookie);
+
+    HRESULT (STDMETHODCALLTYPE *RegisterOcclusionStatusEvent)(
+        IDXGIFactory4 *This,
+        HANDLE event,
+        DWORD *cookie);
+
+    void (STDMETHODCALLTYPE *UnregisterOcclusionStatus)(
+        IDXGIFactory4 *This,
+        DWORD cookie);
+
+    HRESULT (STDMETHODCALLTYPE *CreateSwapChainForComposition)(
+        IDXGIFactory4 *This,
+        IUnknown *device,
+        const DXGI_SWAP_CHAIN_DESC1 *desc,
+        IDXGIOutput *output,
+        IDXGISwapChain1 **swapchain);
+
+    /*** IDXGIFactory3 methods ***/
+    UINT (STDMETHODCALLTYPE *GetCreationFlags)(
+        IDXGIFactory4 *This);
+
+    /*** IDXGIFactory4 methods ***/
+    HRESULT (STDMETHODCALLTYPE *EnumAdapterByLuid)(
+        IDXGIFactory4 *This,
+        LUID luid,
+        REFIID iid,
+        void **adapter);
+
+    HRESULT (STDMETHODCALLTYPE *EnumWarpAdapter)(
+        IDXGIFactory4 *This,
+        REFIID iid,
+        void **adapter);
+
+    END_INTERFACE
+} IDXGIFactory4Vtbl;
+
+interface IDXGIFactory4 {
+    CONST_VTBL IDXGIFactory4Vtbl* lpVtbl;
+};
+
+#ifdef COBJMACROS
+#ifndef WIDL_C_INLINE_WRAPPERS
+/*** IUnknown methods ***/
+#define IDXGIFactory4_QueryInterface(This,riid,object) (This)->lpVtbl->QueryInterface(This,riid,object)
+#define IDXGIFactory4_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDXGIFactory4_Release(This) (This)->lpVtbl->Release(This)
+/*** IDXGIObject methods ***/
+#define IDXGIFactory4_SetPrivateData(This,name,data_size,data) (This)->lpVtbl->SetPrivateData(This,name,data_size,data)
+#define IDXGIFactory4_GetPrivateDataInterface(This,name,unknown) (This)->lpVtbl->GetPrivateDataInterface(This,name,unknown)
+#define IDXGIFactory4_GetPrivateData(This,name,data_size,data) (This)->lpVtbl->GetPrivateData(This,name,data_size,data)
+#define IDXGIFactory4_GetParent(This,riid,parent) (This)->lpVtbl->GetParent(This,riid,parent)
+/*** IDXGIFactory methods ***/
+#define IDXGIFactory4_EnumAdapters(This,adapter_idx,adapter) (This)->lpVtbl->EnumAdapters(This,adapter_idx,adapter)
+#define IDXGIFactory4_MakeWindowAssociation(This,hwnd,flags) (This)->lpVtbl->MakeWindowAssociation(This,hwnd,flags)
+#define IDXGIFactory4_GetWindowAssociation(This,hwnd) (This)->lpVtbl->GetWindowAssociation(This,hwnd)
+#define IDXGIFactory4_CreateSwapChain(This,device,desc,swapchain) (This)->lpVtbl->CreateSwapChain(This,device,desc,swapchain)
+#define IDXGIFactory4_CreateSoftwareAdapter(This,hmodule,adapter) (This)->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter)
+/*** IDXGIFactory1 methods ***/
+#define IDXGIFactory4_EnumAdapters1(This,adapter_idx,adpter) (This)->lpVtbl->EnumAdapters1(This,adapter_idx,adpter)
+#define IDXGIFactory4_IsCurrent(This) (This)->lpVtbl->IsCurrent(This)
+/*** IDXGIFactory2 methods ***/
+#define IDXGIFactory4_IsWindowedStereoEnabled(This) (This)->lpVtbl->IsWindowedStereoEnabled(This)
+#define IDXGIFactory4_CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain)
+#define IDXGIFactory4_CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain)
+#define IDXGIFactory4_GetSharedResourceAdapterLuid(This,resource,luid) (This)->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid)
+#define IDXGIFactory4_RegisterStereoStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory4_RegisterStereoStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterStereoStatusEvent(This,event,cookie)
+#define IDXGIFactory4_UnregisterStereoStatus(This,cookie) (This)->lpVtbl->UnregisterStereoStatus(This,cookie)
+#define IDXGIFactory4_RegisterOcclusionStatusWindow(This,window,msg,cookie) (This)->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie)
+#define IDXGIFactory4_RegisterOcclusionStatusEvent(This,event,cookie) (This)->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie)
+#define IDXGIFactory4_UnregisterOcclusionStatus(This,cookie) (This)->lpVtbl->UnregisterOcclusionStatus(This,cookie)
+#define IDXGIFactory4_CreateSwapChainForComposition(This,device,desc,output,swapchain) (This)->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain)
+/*** IDXGIFactory3 methods ***/
+#define IDXGIFactory4_GetCreationFlags(This) (This)->lpVtbl->GetCreationFlags(This)
+/*** IDXGIFactory4 methods ***/
+#define IDXGIFactory4_EnumAdapterByLuid(This,luid,iid,adapter) (This)->lpVtbl->EnumAdapterByLuid(This,luid,iid,adapter)
+#define IDXGIFactory4_EnumWarpAdapter(This,iid,adapter) (This)->lpVtbl->EnumWarpAdapter(This,iid,adapter)
+#else
+/*** IUnknown methods ***/
+static FORCEINLINE HRESULT IDXGIFactory4_QueryInterface(IDXGIFactory4* This,REFIID riid,void **object) {
+    return This->lpVtbl->QueryInterface(This,riid,object);
+}
+static FORCEINLINE ULONG IDXGIFactory4_AddRef(IDXGIFactory4* This) {
+    return This->lpVtbl->AddRef(This);
+}
+static FORCEINLINE ULONG IDXGIFactory4_Release(IDXGIFactory4* This) {
+    return This->lpVtbl->Release(This);
+}
+/*** IDXGIObject methods ***/
+static FORCEINLINE HRESULT IDXGIFactory4_SetPrivateData(IDXGIFactory4* This,REFGUID name,UINT data_size,const void *data) {
+    return This->lpVtbl->SetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_GetPrivateDataInterface(IDXGIFactory4* This,REFGUID name,const IUnknown *unknown) {
+    return This->lpVtbl->GetPrivateDataInterface(This,name,unknown);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_GetPrivateData(IDXGIFactory4* This,REFGUID name,UINT *data_size,void *data) {
+    return This->lpVtbl->GetPrivateData(This,name,data_size,data);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_GetParent(IDXGIFactory4* This,REFIID riid,void **parent) {
+    return This->lpVtbl->GetParent(This,riid,parent);
+}
+/*** IDXGIFactory methods ***/
+static FORCEINLINE HRESULT IDXGIFactory4_EnumAdapters(IDXGIFactory4* This,UINT adapter_idx,IDXGIAdapter **adapter) {
+    return This->lpVtbl->EnumAdapters(This,adapter_idx,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_MakeWindowAssociation(IDXGIFactory4* This,HWND hwnd,UINT flags) {
+    return This->lpVtbl->MakeWindowAssociation(This,hwnd,flags);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_GetWindowAssociation(IDXGIFactory4* This,HWND *hwnd) {
+    return This->lpVtbl->GetWindowAssociation(This,hwnd);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_CreateSwapChain(IDXGIFactory4* This,IUnknown *device,DXGI_SWAP_CHAIN_DESC *desc,IDXGISwapChain **swapchain) {
+    return This->lpVtbl->CreateSwapChain(This,device,desc,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_CreateSoftwareAdapter(IDXGIFactory4* This,HMODULE hmodule,IDXGIAdapter **adapter) {
+    return This->lpVtbl->CreateSoftwareAdapter(This,hmodule,adapter);
+}
+/*** IDXGIFactory1 methods ***/
+static FORCEINLINE HRESULT IDXGIFactory4_EnumAdapters1(IDXGIFactory4* This,UINT adapter_idx,IDXGIAdapter1 **adpter) {
+    return This->lpVtbl->EnumAdapters1(This,adapter_idx,adpter);
+}
+static FORCEINLINE BOOL IDXGIFactory4_IsCurrent(IDXGIFactory4* This) {
+    return This->lpVtbl->IsCurrent(This);
+}
+/*** IDXGIFactory2 methods ***/
+static FORCEINLINE BOOL IDXGIFactory4_IsWindowedStereoEnabled(IDXGIFactory4* This) {
+    return This->lpVtbl->IsWindowedStereoEnabled(This);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_CreateSwapChainForHwnd(IDXGIFactory4* This,IUnknown *device,HWND window,const DXGI_SWAP_CHAIN_DESC1 *desc,const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForHwnd(This,device,window,desc,fullscreen_desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_CreateSwapChainForCoreWindow(IDXGIFactory4* This,IUnknown *device,IUnknown *window,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForCoreWindow(This,device,window,desc,output,swapchain);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_GetSharedResourceAdapterLuid(IDXGIFactory4* This,HANDLE resource,LUID *luid) {
+    return This->lpVtbl->GetSharedResourceAdapterLuid(This,resource,luid);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_RegisterStereoStatusWindow(IDXGIFactory4* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_RegisterStereoStatusEvent(IDXGIFactory4* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterStereoStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory4_UnregisterStereoStatus(IDXGIFactory4* This,DWORD cookie) {
+    This->lpVtbl->UnregisterStereoStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_RegisterOcclusionStatusWindow(IDXGIFactory4* This,HWND window,UINT msg,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusWindow(This,window,msg,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_RegisterOcclusionStatusEvent(IDXGIFactory4* This,HANDLE event,DWORD *cookie) {
+    return This->lpVtbl->RegisterOcclusionStatusEvent(This,event,cookie);
+}
+static FORCEINLINE void IDXGIFactory4_UnregisterOcclusionStatus(IDXGIFactory4* This,DWORD cookie) {
+    This->lpVtbl->UnregisterOcclusionStatus(This,cookie);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_CreateSwapChainForComposition(IDXGIFactory4* This,IUnknown *device,const DXGI_SWAP_CHAIN_DESC1 *desc,IDXGIOutput *output,IDXGISwapChain1 **swapchain) {
+    return This->lpVtbl->CreateSwapChainForComposition(This,device,desc,output,swapchain);
+}
+/*** IDXGIFactory3 methods ***/
+static FORCEINLINE UINT IDXGIFactory4_GetCreationFlags(IDXGIFactory4* This) {
+    return This->lpVtbl->GetCreationFlags(This);
+}
+/*** IDXGIFactory4 methods ***/
+static FORCEINLINE HRESULT IDXGIFactory4_EnumAdapterByLuid(IDXGIFactory4* This,LUID luid,REFIID iid,void **adapter) {
+    return This->lpVtbl->EnumAdapterByLuid(This,luid,iid,adapter);
+}
+static FORCEINLINE HRESULT IDXGIFactory4_EnumWarpAdapter(IDXGIFactory4* This,REFIID iid,void **adapter) {
+    return This->lpVtbl->EnumWarpAdapter(This,iid,adapter);
+}
+#endif
+#endif
+
+#endif
+
+
+#endif  /* __IDXGIFactory4_INTERFACE_DEFINED__ */
+
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgi1_4_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgi1_4.idl b/dlls/vkd3d/include/vkd3d_dxgi1_4.idl
new file mode 100644
index 00000000000..ccd2224c82d
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgi1_4.idl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_dxgi1_3.idl";
+
+[
+    local,
+    object,
+    uuid(94d99bdb-f1f8-4ab0-b236-7da0170edab1),
+    pointer_default(unique)
+]
+interface IDXGISwapChain3 : IDXGISwapChain2
+{
+    UINT GetCurrentBackBufferIndex();
+    HRESULT CheckColorSpaceSupport(DXGI_COLOR_SPACE_TYPE type, UINT *support);
+    HRESULT SetColorSpace1(DXGI_COLOR_SPACE_TYPE type);
+    HRESULT ResizeBuffers1(UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format,
+            UINT flags, const UINT *node_mask, IUnknown *const *present_queue);
+}
+
+[
+    local,
+    object,
+    uuid(1bc6ea02-ef36-464f-bf0c-21ca39e5168a),
+    pointer_default(unique),
+]
+interface IDXGIFactory4 : IDXGIFactory3
+{
+    HRESULT EnumAdapterByLuid(LUID luid, REFIID iid, void **adapter);
+    HRESULT EnumWarpAdapter(REFIID iid, void **adapter);
+}
diff --git a/dlls/vkd3d/include/vkd3d_dxgibase.h b/dlls/vkd3d/include/vkd3d_dxgibase.h
new file mode 100644
index 00000000000..31e686a2640
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgibase.h
@@ -0,0 +1,49 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgibase.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgibase_h__
+#define __vkd3d_dxgibase_h__
+
+/* Forward declarations */
+
+/* Headers for imported files */
+
+#include <vkd3d_windows.h>
+#include <vkd3d_dxgiformat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DXGI_ERROR_INVALID_CALL
+#define DXGI_ERROR_INVALID_CALL   _HRESULT_TYPEDEF_(0x887a0001)
+#endif
+#ifndef DXGI_ERROR_DEVICE_REMOVED
+#define DXGI_ERROR_DEVICE_REMOVED _HRESULT_TYPEDEF_(0x887a0005)
+#endif
+typedef struct DXGI_SAMPLE_DESC {
+    UINT Count;
+    UINT Quality;
+} DXGI_SAMPLE_DESC;
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgibase_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgibase.idl b/dlls/vkd3d/include/vkd3d_dxgibase.idl
new file mode 100644
index 00000000000..93f931e0944
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgibase.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_windows.h";
+
+import "vkd3d_dxgiformat.idl";
+
+cpp_quote("#ifndef DXGI_ERROR_INVALID_CALL")
+cpp_quote("#define DXGI_ERROR_INVALID_CALL   _HRESULT_TYPEDEF_(0x887a0001)")
+cpp_quote("#endif")
+cpp_quote("#ifndef DXGI_ERROR_DEVICE_REMOVED")
+cpp_quote("#define DXGI_ERROR_DEVICE_REMOVED _HRESULT_TYPEDEF_(0x887a0005)")
+cpp_quote("#endif")
+
+typedef struct DXGI_SAMPLE_DESC
+{
+    UINT Count;
+    UINT Quality;
+} DXGI_SAMPLE_DESC;
diff --git a/dlls/vkd3d/include/vkd3d_dxgiformat.h b/dlls/vkd3d/include/vkd3d_dxgiformat.h
new file mode 100644
index 00000000000..f0bf0774969
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgiformat.h
@@ -0,0 +1,156 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgiformat.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgiformat_h__
+#define __vkd3d_dxgiformat_h__
+
+/* Forward declarations */
+
+/* Headers for imported files */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum DXGI_FORMAT {
+    DXGI_FORMAT_UNKNOWN = 0x0,
+    DXGI_FORMAT_R32G32B32A32_TYPELESS = 0x1,
+    DXGI_FORMAT_R32G32B32A32_FLOAT = 0x2,
+    DXGI_FORMAT_R32G32B32A32_UINT = 0x3,
+    DXGI_FORMAT_R32G32B32A32_SINT = 0x4,
+    DXGI_FORMAT_R32G32B32_TYPELESS = 0x5,
+    DXGI_FORMAT_R32G32B32_FLOAT = 0x6,
+    DXGI_FORMAT_R32G32B32_UINT = 0x7,
+    DXGI_FORMAT_R32G32B32_SINT = 0x8,
+    DXGI_FORMAT_R16G16B16A16_TYPELESS = 0x9,
+    DXGI_FORMAT_R16G16B16A16_FLOAT = 0xa,
+    DXGI_FORMAT_R16G16B16A16_UNORM = 0xb,
+    DXGI_FORMAT_R16G16B16A16_UINT = 0xc,
+    DXGI_FORMAT_R16G16B16A16_SNORM = 0xd,
+    DXGI_FORMAT_R16G16B16A16_SINT = 0xe,
+    DXGI_FORMAT_R32G32_TYPELESS = 0xf,
+    DXGI_FORMAT_R32G32_FLOAT = 0x10,
+    DXGI_FORMAT_R32G32_UINT = 0x11,
+    DXGI_FORMAT_R32G32_SINT = 0x12,
+    DXGI_FORMAT_R32G8X24_TYPELESS = 0x13,
+    DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 0x14,
+    DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 0x15,
+    DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 0x16,
+    DXGI_FORMAT_R10G10B10A2_TYPELESS = 0x17,
+    DXGI_FORMAT_R10G10B10A2_UNORM = 0x18,
+    DXGI_FORMAT_R10G10B10A2_UINT = 0x19,
+    DXGI_FORMAT_R11G11B10_FLOAT = 0x1a,
+    DXGI_FORMAT_R8G8B8A8_TYPELESS = 0x1b,
+    DXGI_FORMAT_R8G8B8A8_UNORM = 0x1c,
+    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 0x1d,
+    DXGI_FORMAT_R8G8B8A8_UINT = 0x1e,
+    DXGI_FORMAT_R8G8B8A8_SNORM = 0x1f,
+    DXGI_FORMAT_R8G8B8A8_SINT = 0x20,
+    DXGI_FORMAT_R16G16_TYPELESS = 0x21,
+    DXGI_FORMAT_R16G16_FLOAT = 0x22,
+    DXGI_FORMAT_R16G16_UNORM = 0x23,
+    DXGI_FORMAT_R16G16_UINT = 0x24,
+    DXGI_FORMAT_R16G16_SNORM = 0x25,
+    DXGI_FORMAT_R16G16_SINT = 0x26,
+    DXGI_FORMAT_R32_TYPELESS = 0x27,
+    DXGI_FORMAT_D32_FLOAT = 0x28,
+    DXGI_FORMAT_R32_FLOAT = 0x29,
+    DXGI_FORMAT_R32_UINT = 0x2a,
+    DXGI_FORMAT_R32_SINT = 0x2b,
+    DXGI_FORMAT_R24G8_TYPELESS = 0x2c,
+    DXGI_FORMAT_D24_UNORM_S8_UINT = 0x2d,
+    DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 0x2e,
+    DXGI_FORMAT_X24_TYPELESS_G8_UINT = 0x2f,
+    DXGI_FORMAT_R8G8_TYPELESS = 0x30,
+    DXGI_FORMAT_R8G8_UNORM = 0x31,
+    DXGI_FORMAT_R8G8_UINT = 0x32,
+    DXGI_FORMAT_R8G8_SNORM = 0x33,
+    DXGI_FORMAT_R8G8_SINT = 0x34,
+    DXGI_FORMAT_R16_TYPELESS = 0x35,
+    DXGI_FORMAT_R16_FLOAT = 0x36,
+    DXGI_FORMAT_D16_UNORM = 0x37,
+    DXGI_FORMAT_R16_UNORM = 0x38,
+    DXGI_FORMAT_R16_UINT = 0x39,
+    DXGI_FORMAT_R16_SNORM = 0x3a,
+    DXGI_FORMAT_R16_SINT = 0x3b,
+    DXGI_FORMAT_R8_TYPELESS = 0x3c,
+    DXGI_FORMAT_R8_UNORM = 0x3d,
+    DXGI_FORMAT_R8_UINT = 0x3e,
+    DXGI_FORMAT_R8_SNORM = 0x3f,
+    DXGI_FORMAT_R8_SINT = 0x40,
+    DXGI_FORMAT_A8_UNORM = 0x41,
+    DXGI_FORMAT_R1_UNORM = 0x42,
+    DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 0x43,
+    DXGI_FORMAT_R8G8_B8G8_UNORM = 0x44,
+    DXGI_FORMAT_G8R8_G8B8_UNORM = 0x45,
+    DXGI_FORMAT_BC1_TYPELESS = 0x46,
+    DXGI_FORMAT_BC1_UNORM = 0x47,
+    DXGI_FORMAT_BC1_UNORM_SRGB = 0x48,
+    DXGI_FORMAT_BC2_TYPELESS = 0x49,
+    DXGI_FORMAT_BC2_UNORM = 0x4a,
+    DXGI_FORMAT_BC2_UNORM_SRGB = 0x4b,
+    DXGI_FORMAT_BC3_TYPELESS = 0x4c,
+    DXGI_FORMAT_BC3_UNORM = 0x4d,
+    DXGI_FORMAT_BC3_UNORM_SRGB = 0x4e,
+    DXGI_FORMAT_BC4_TYPELESS = 0x4f,
+    DXGI_FORMAT_BC4_UNORM = 0x50,
+    DXGI_FORMAT_BC4_SNORM = 0x51,
+    DXGI_FORMAT_BC5_TYPELESS = 0x52,
+    DXGI_FORMAT_BC5_UNORM = 0x53,
+    DXGI_FORMAT_BC5_SNORM = 0x54,
+    DXGI_FORMAT_B5G6R5_UNORM = 0x55,
+    DXGI_FORMAT_B5G5R5A1_UNORM = 0x56,
+    DXGI_FORMAT_B8G8R8A8_UNORM = 0x57,
+    DXGI_FORMAT_B8G8R8X8_UNORM = 0x58,
+    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 0x59,
+    DXGI_FORMAT_B8G8R8A8_TYPELESS = 0x5a,
+    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 0x5b,
+    DXGI_FORMAT_B8G8R8X8_TYPELESS = 0x5c,
+    DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 0x5d,
+    DXGI_FORMAT_BC6H_TYPELESS = 0x5e,
+    DXGI_FORMAT_BC6H_UF16 = 0x5f,
+    DXGI_FORMAT_BC6H_SF16 = 0x60,
+    DXGI_FORMAT_BC7_TYPELESS = 0x61,
+    DXGI_FORMAT_BC7_UNORM = 0x62,
+    DXGI_FORMAT_BC7_UNORM_SRGB = 0x63,
+    DXGI_FORMAT_AYUV = 0x64,
+    DXGI_FORMAT_Y410 = 0x65,
+    DXGI_FORMAT_Y416 = 0x66,
+    DXGI_FORMAT_NV12 = 0x67,
+    DXGI_FORMAT_P010 = 0x68,
+    DXGI_FORMAT_P016 = 0x69,
+    DXGI_FORMAT_420_OPAQUE = 0x6a,
+    DXGI_FORMAT_YUY2 = 0x6b,
+    DXGI_FORMAT_Y210 = 0x6c,
+    DXGI_FORMAT_Y216 = 0x6d,
+    DXGI_FORMAT_NV11 = 0x6e,
+    DXGI_FORMAT_AI44 = 0x6f,
+    DXGI_FORMAT_IA44 = 0x70,
+    DXGI_FORMAT_P8 = 0x71,
+    DXGI_FORMAT_A8P8 = 0x72,
+    DXGI_FORMAT_B4G4R4A4_UNORM = 0x73,
+    DXGI_FORMAT_FORCE_UINT = 0xffffffff
+} DXGI_FORMAT;
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgiformat_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgiformat.idl b/dlls/vkd3d/include/vkd3d_dxgiformat.idl
new file mode 100644
index 00000000000..63129bbefa1
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgiformat.idl
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+typedef enum DXGI_FORMAT
+{
+    DXGI_FORMAT_UNKNOWN                     = 0x00,
+    DXGI_FORMAT_R32G32B32A32_TYPELESS       = 0x01,
+    DXGI_FORMAT_R32G32B32A32_FLOAT          = 0x02,
+    DXGI_FORMAT_R32G32B32A32_UINT           = 0x03,
+    DXGI_FORMAT_R32G32B32A32_SINT           = 0x04,
+    DXGI_FORMAT_R32G32B32_TYPELESS          = 0x05,
+    DXGI_FORMAT_R32G32B32_FLOAT             = 0x06,
+    DXGI_FORMAT_R32G32B32_UINT              = 0x07,
+    DXGI_FORMAT_R32G32B32_SINT              = 0x08,
+    DXGI_FORMAT_R16G16B16A16_TYPELESS       = 0x09,
+    DXGI_FORMAT_R16G16B16A16_FLOAT          = 0x0a,
+    DXGI_FORMAT_R16G16B16A16_UNORM          = 0x0b,
+    DXGI_FORMAT_R16G16B16A16_UINT           = 0x0c,
+    DXGI_FORMAT_R16G16B16A16_SNORM          = 0x0d,
+    DXGI_FORMAT_R16G16B16A16_SINT           = 0x0e,
+    DXGI_FORMAT_R32G32_TYPELESS             = 0x0f,
+    DXGI_FORMAT_R32G32_FLOAT                = 0x10,
+    DXGI_FORMAT_R32G32_UINT                 = 0x11,
+    DXGI_FORMAT_R32G32_SINT                 = 0x12,
+    DXGI_FORMAT_R32G8X24_TYPELESS           = 0x13,
+    DXGI_FORMAT_D32_FLOAT_S8X24_UINT        = 0x14,
+    DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS    = 0x15,
+    DXGI_FORMAT_X32_TYPELESS_G8X24_UINT     = 0x16,
+    DXGI_FORMAT_R10G10B10A2_TYPELESS        = 0x17,
+    DXGI_FORMAT_R10G10B10A2_UNORM           = 0x18,
+    DXGI_FORMAT_R10G10B10A2_UINT            = 0x19,
+    DXGI_FORMAT_R11G11B10_FLOAT             = 0x1a,
+    DXGI_FORMAT_R8G8B8A8_TYPELESS           = 0x1b,
+    DXGI_FORMAT_R8G8B8A8_UNORM              = 0x1c,
+    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB         = 0x1d,
+    DXGI_FORMAT_R8G8B8A8_UINT               = 0x1e,
+    DXGI_FORMAT_R8G8B8A8_SNORM              = 0x1f,
+    DXGI_FORMAT_R8G8B8A8_SINT               = 0x20,
+    DXGI_FORMAT_R16G16_TYPELESS             = 0x21,
+    DXGI_FORMAT_R16G16_FLOAT                = 0x22,
+    DXGI_FORMAT_R16G16_UNORM                = 0x23,
+    DXGI_FORMAT_R16G16_UINT                 = 0x24,
+    DXGI_FORMAT_R16G16_SNORM                = 0x25,
+    DXGI_FORMAT_R16G16_SINT                 = 0x26,
+    DXGI_FORMAT_R32_TYPELESS                = 0x27,
+    DXGI_FORMAT_D32_FLOAT                   = 0x28,
+    DXGI_FORMAT_R32_FLOAT                   = 0x29,
+    DXGI_FORMAT_R32_UINT                    = 0x2a,
+    DXGI_FORMAT_R32_SINT                    = 0x2b,
+    DXGI_FORMAT_R24G8_TYPELESS              = 0x2c,
+    DXGI_FORMAT_D24_UNORM_S8_UINT           = 0x2d,
+    DXGI_FORMAT_R24_UNORM_X8_TYPELESS       = 0x2e,
+    DXGI_FORMAT_X24_TYPELESS_G8_UINT        = 0x2f,
+    DXGI_FORMAT_R8G8_TYPELESS               = 0x30,
+    DXGI_FORMAT_R8G8_UNORM                  = 0x31,
+    DXGI_FORMAT_R8G8_UINT                   = 0x32,
+    DXGI_FORMAT_R8G8_SNORM                  = 0x33,
+    DXGI_FORMAT_R8G8_SINT                   = 0x34,
+    DXGI_FORMAT_R16_TYPELESS                = 0x35,
+    DXGI_FORMAT_R16_FLOAT                   = 0x36,
+    DXGI_FORMAT_D16_UNORM                   = 0x37,
+    DXGI_FORMAT_R16_UNORM                   = 0x38,
+    DXGI_FORMAT_R16_UINT                    = 0x39,
+    DXGI_FORMAT_R16_SNORM                   = 0x3a,
+    DXGI_FORMAT_R16_SINT                    = 0x3b,
+    DXGI_FORMAT_R8_TYPELESS                 = 0x3c,
+    DXGI_FORMAT_R8_UNORM                    = 0x3d,
+    DXGI_FORMAT_R8_UINT                     = 0x3e,
+    DXGI_FORMAT_R8_SNORM                    = 0x3f,
+    DXGI_FORMAT_R8_SINT                     = 0x40,
+    DXGI_FORMAT_A8_UNORM                    = 0x41,
+    DXGI_FORMAT_R1_UNORM                    = 0x42,
+    DXGI_FORMAT_R9G9B9E5_SHAREDEXP          = 0x43,
+    DXGI_FORMAT_R8G8_B8G8_UNORM             = 0x44,
+    DXGI_FORMAT_G8R8_G8B8_UNORM             = 0x45,
+    DXGI_FORMAT_BC1_TYPELESS                = 0x46,
+    DXGI_FORMAT_BC1_UNORM                   = 0x47,
+    DXGI_FORMAT_BC1_UNORM_SRGB              = 0x48,
+    DXGI_FORMAT_BC2_TYPELESS                = 0x49,
+    DXGI_FORMAT_BC2_UNORM                   = 0x4a,
+    DXGI_FORMAT_BC2_UNORM_SRGB              = 0x4b,
+    DXGI_FORMAT_BC3_TYPELESS                = 0x4c,
+    DXGI_FORMAT_BC3_UNORM                   = 0x4d,
+    DXGI_FORMAT_BC3_UNORM_SRGB              = 0x4e,
+    DXGI_FORMAT_BC4_TYPELESS                = 0x4f,
+    DXGI_FORMAT_BC4_UNORM                   = 0x50,
+    DXGI_FORMAT_BC4_SNORM                   = 0x51,
+    DXGI_FORMAT_BC5_TYPELESS                = 0x52,
+    DXGI_FORMAT_BC5_UNORM                   = 0x53,
+    DXGI_FORMAT_BC5_SNORM                   = 0x54,
+    DXGI_FORMAT_B5G6R5_UNORM                = 0x55,
+    DXGI_FORMAT_B5G5R5A1_UNORM              = 0x56,
+    DXGI_FORMAT_B8G8R8A8_UNORM              = 0x57,
+    DXGI_FORMAT_B8G8R8X8_UNORM              = 0x58,
+    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM  = 0x59,
+    DXGI_FORMAT_B8G8R8A8_TYPELESS           = 0x5a,
+    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB         = 0x5b,
+    DXGI_FORMAT_B8G8R8X8_TYPELESS           = 0x5c,
+    DXGI_FORMAT_B8G8R8X8_UNORM_SRGB         = 0x5d,
+    DXGI_FORMAT_BC6H_TYPELESS               = 0x5e,
+    DXGI_FORMAT_BC6H_UF16                   = 0x5f,
+    DXGI_FORMAT_BC6H_SF16                   = 0x60,
+    DXGI_FORMAT_BC7_TYPELESS                = 0x61,
+    DXGI_FORMAT_BC7_UNORM                   = 0x62,
+    DXGI_FORMAT_BC7_UNORM_SRGB              = 0x63,
+    DXGI_FORMAT_AYUV                        = 0x64,
+    DXGI_FORMAT_Y410                        = 0x65,
+    DXGI_FORMAT_Y416                        = 0x66,
+    DXGI_FORMAT_NV12                        = 0x67,
+    DXGI_FORMAT_P010                        = 0x68,
+    DXGI_FORMAT_P016                        = 0x69,
+    DXGI_FORMAT_420_OPAQUE                  = 0x6a,
+    DXGI_FORMAT_YUY2                        = 0x6b,
+    DXGI_FORMAT_Y210                        = 0x6c,
+    DXGI_FORMAT_Y216                        = 0x6d,
+    DXGI_FORMAT_NV11                        = 0x6e,
+    DXGI_FORMAT_AI44                        = 0x6f,
+    DXGI_FORMAT_IA44                        = 0x70,
+    DXGI_FORMAT_P8                          = 0x71,
+    DXGI_FORMAT_A8P8                        = 0x72,
+    DXGI_FORMAT_B4G4R4A4_UNORM              = 0x73,
+
+    DXGI_FORMAT_FORCE_UINT                  = 0xffffffff,
+} DXGI_FORMAT;
diff --git a/dlls/vkd3d/include/vkd3d_dxgitype.h b/dlls/vkd3d/include/vkd3d_dxgitype.h
new file mode 100644
index 00000000000..b1761b52770
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgitype.h
@@ -0,0 +1,57 @@
+/*** Autogenerated by WIDL 5.17 from include/vkd3d_dxgitype.idl - Do not edit ***/
+
+#ifdef _WIN32
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
+
+#ifndef COM_NO_WINDOWS_H
+#include <windows.h>
+#include <ole2.h>
+#endif
+
+#ifndef __vkd3d_dxgitype_h__
+#define __vkd3d_dxgitype_h__
+
+/* Forward declarations */
+
+/* Headers for imported files */
+
+#include <vkd3d_windows.h>
+#include <vkd3d_dxgibase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum DXGI_COLOR_SPACE_TYPE {
+    DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0x0,
+    DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 0x1,
+    DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 0x2,
+    DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 0x3,
+    DXGI_COLOR_SPACE_RESERVED = 0x4,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 0x5,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 0x6,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 0x7,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 0x8,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 0x9,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 0xa,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 0xb,
+    DXGI_COLOR_SPACE_CUSTOM = 0xffffffff
+} DXGI_COLOR_SPACE_TYPE;
+typedef struct _D3DCOLORVALUE D3DCOLORVALUE;
+typedef struct _D3DCOLORVALUE DXGI_RGBA;
+typedef struct DXGI_MODE_DESC DXGI_MODE_DESC;
+/* Begin additional prototypes for all interfaces */
+
+
+/* End additional prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __vkd3d_dxgitype_h__ */
diff --git a/dlls/vkd3d/include/vkd3d_dxgitype.idl b/dlls/vkd3d/include/vkd3d_dxgitype.idl
new file mode 100644
index 00000000000..74806c0ce41
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_dxgitype.idl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "vkd3d_windows.h";
+import "vkd3d_dxgibase.idl";
+
+typedef enum DXGI_COLOR_SPACE_TYPE
+{
+    DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709        = 0x0,
+    DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709        = 0x1,
+    DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709      = 0x2,
+    DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020     = 0x3,
+    DXGI_COLOR_SPACE_RESERVED                      = 0x4,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 0x5,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601    = 0x6,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601      = 0x7,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709    = 0x8,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709      = 0x9,
+    DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020   = 0xa,
+    DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020     = 0xb,
+    DXGI_COLOR_SPACE_CUSTOM                        = 0xffffffff,
+} DXGI_COLOR_SPACE_TYPE;
+
+typedef struct _D3DCOLORVALUE D3DCOLORVALUE, DXGI_RGBA;
+typedef struct DXGI_MODE_DESC DXGI_MODE_DESC;
diff --git a/dlls/vkd3d/include/vkd3d_shader.h b/dlls/vkd3d/include/vkd3d_shader.h
new file mode 100644
index 00000000000..3efd355fda3
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_shader.h
@@ -0,0 +1,1502 @@
+/*
+ * Copyright 2017-2019 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_SHADER_H
+#define __VKD3D_SHADER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <vkd3d_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+/**
+ * \file vkd3d_shader.h
+ *
+ * \since 1.2
+ *
+ * This file contains definitions for the vkd3d-shader library.
+ *
+ * The vkd3d-shader library provides multiple utilities related to the
+ * compilation, transformation, and reflection of GPU shaders.
+ */
+
+/** The type of a chained structure. */
+enum vkd3d_shader_structure_type
+{
+    /** The structure is a vkd3d_shader_compile_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO,
+    /** The structure is a vkd3d_shader_interface_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO,
+    /** The structure is a vkd3d_shader_scan_descriptor_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO,
+    /** The structure is a vkd3d_shader_spirv_domain_shader_target_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_DOMAIN_SHADER_TARGET_INFO,
+    /** The structure is a vkd3d_shader_spirv_target_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO,
+    /** The structure is a vkd3d_shader_transform_feedback_info structure. */
+    VKD3D_SHADER_STRUCTURE_TYPE_TRANSFORM_FEEDBACK_INFO,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE),
+};
+
+/**
+ * Determines how buffer UAVs are stored.
+ *
+ * This also affects UAV counters in Vulkan environments. In OpenGL
+ * environments, atomic counter buffers are always used for UAV counters.
+ */
+enum vkd3d_shader_compile_option_buffer_uav
+{
+    /** Use buffer textures for buffer UAVs. This is the default value. */
+    VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_TEXEL_BUFFER = 0x00000000,
+    /** Use storage buffers for buffer UAVs. */
+    VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_BUFFER       = 0x00000001,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV),
+};
+
+enum vkd3d_shader_compile_option_formatting_flags
+{
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_NONE    = 0x00000000,
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_COLOUR  = 0x00000001,
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT  = 0x00000002,
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_OFFSETS = 0x00000004,
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_HEADER  = 0x00000008,
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING_RAW_IDS = 0x00000010,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FORMATTING_FLAGS),
+};
+
+enum vkd3d_shader_compile_option_name
+{
+    /**
+     * If \a value is nonzero, do not include debug information in the
+     * compiled shader. The default value is zero.
+     *
+     * This option is supported by vkd3d_shader_compile(). However, not all
+     * compilers support generating debug information.
+     */
+    VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG = 0x00000001,
+    /** \a value is a member of enum vkd3d_shader_compile_option_buffer_uav. */
+    VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV  = 0x00000002,
+    /** \a value is a member of enum vkd3d_shader_compile_option_formatting_flags. */
+    VKD3D_SHADER_COMPILE_OPTION_FORMATTING  = 0x00000003,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME),
+};
+
+/**
+ * Various settings which may affect shader compilation or scanning, passed as
+ * part of struct vkd3d_shader_compile_info. For more details, see the
+ * documentation for individual options.
+ */
+struct vkd3d_shader_compile_option
+{
+    /** Name of the option. */
+    enum vkd3d_shader_compile_option_name name;
+    /**
+     * A value associated with the option. The type and interpretation of the
+     * value depends on the option in question.
+     */
+    unsigned int value;
+};
+
+/** Describes which shader stages a resource is visible to. */
+enum vkd3d_shader_visibility
+{
+    /** The resource is visible to all shader stages. */
+    VKD3D_SHADER_VISIBILITY_ALL = 0,
+    /** The resource is visible only to the vertex shader. */
+    VKD3D_SHADER_VISIBILITY_VERTEX = 1,
+    /** The resource is visible only to the hull shader. */
+    VKD3D_SHADER_VISIBILITY_HULL = 2,
+    /** The resource is visible only to the domain shader. */
+    VKD3D_SHADER_VISIBILITY_DOMAIN = 3,
+    /** The resource is visible only to the geometry shader. */
+    VKD3D_SHADER_VISIBILITY_GEOMETRY = 4,
+    /** The resource is visible only to the pixel shader. */
+    VKD3D_SHADER_VISIBILITY_PIXEL = 5,
+
+    /** The resource is visible only to the compute shader. */
+    VKD3D_SHADER_VISIBILITY_COMPUTE = 1000000000,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_VISIBILITY),
+};
+
+/** A generic structure containing a GPU shader, in text or byte-code format. */
+struct vkd3d_shader_code
+{
+    /** Pointer to the code. */
+    const void *code;
+    /** Size of \a code, in bytes. */
+    size_t size;
+};
+
+/** The type of a shader resource descriptor. */
+enum vkd3d_shader_descriptor_type
+{
+    /**
+     * The descriptor is a shader resource view. In Direct3D assembly, this is
+     * bound to a t# register.
+     */
+    VKD3D_SHADER_DESCRIPTOR_TYPE_SRV     = 0x0,
+    /**
+     * The descriptor is an unordered access view. In Direct3D assembly, this is
+     * bound to a u# register.
+     */
+    VKD3D_SHADER_DESCRIPTOR_TYPE_UAV     = 0x1,
+    /**
+     * The descriptor is a constant buffer view. In Direct3D assembly, this is
+     * bound to a cb# register.
+     */
+    VKD3D_SHADER_DESCRIPTOR_TYPE_CBV     = 0x2,
+    /**
+     * The descriptor is a sampler. In Direct3D assembly, this is bound to an s#
+     * register.
+     */
+    VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER = 0x3,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_TYPE),
+};
+
+/**
+ * A common structure describing the bind point of a descriptor or descriptor
+ * array in the target environment.
+ */
+struct vkd3d_shader_descriptor_binding
+{
+    /**
+     * The set of the descriptor. If the target environment does not support
+     * descriptor sets, this value must be set to 0.
+     */
+    unsigned int set;
+    /** The binding index of the descriptor. */
+    unsigned int binding;
+    /**
+     * The size of this descriptor array. Descriptor arrays are not supported in
+     * this version of vkd3d-shader, and therefore this value must be 1.
+     */
+    unsigned int count;
+};
+
+enum vkd3d_shader_binding_flag
+{
+    VKD3D_SHADER_BINDING_FLAG_BUFFER = 0x00000001,
+    VKD3D_SHADER_BINDING_FLAG_IMAGE  = 0x00000002,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_BINDING_FLAG),
+};
+
+enum vkd3d_shader_parameter_type
+{
+    VKD3D_SHADER_PARAMETER_TYPE_UNKNOWN,
+    VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT,
+    VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_TYPE),
+};
+
+enum vkd3d_shader_parameter_data_type
+{
+    VKD3D_SHADER_PARAMETER_DATA_TYPE_UNKNOWN,
+    VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_DATA_TYPE),
+};
+
+enum vkd3d_shader_parameter_name
+{
+    VKD3D_SHADER_PARAMETER_NAME_UNKNOWN,
+    VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
+};
+
+struct vkd3d_shader_parameter_immediate_constant
+{
+    union
+    {
+        uint32_t u32;
+    } u;
+};
+
+struct vkd3d_shader_parameter_specialization_constant
+{
+    uint32_t id;
+};
+
+struct vkd3d_shader_parameter
+{
+    enum vkd3d_shader_parameter_name name;
+    enum vkd3d_shader_parameter_type type;
+    enum vkd3d_shader_parameter_data_type data_type;
+    union
+    {
+        struct vkd3d_shader_parameter_immediate_constant immediate_constant;
+        struct vkd3d_shader_parameter_specialization_constant specialization_constant;
+    } u;
+};
+
+/**
+ * Describes the mapping of a single resource or resource array to its binding
+ * point in the target environment.
+ *
+ * For example, to map a Direct3D SRV with register space 2, register "t3" to
+ * a Vulkan descriptor in set 4 and with binding 5, set the following members:
+ * - \a type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV
+ * - \a register_space = 2
+ * - \a register_index = 3
+ * - \a binding.set = 4
+ * - \a binding.binding = 5
+ * - \a binding.count = 1
+ *
+ * This structure is used in struct vkd3d_shader_interface_info.
+ */
+struct vkd3d_shader_resource_binding
+{
+    /** The type of this descriptor. */
+    enum vkd3d_shader_descriptor_type type;
+    /**
+     * Register space of the Direct3D resource. If the source format does not
+     * support multiple register spaces, this parameter must be set to 0.
+     */
+    unsigned int register_space;
+    /** Register index of the DXBC resource. */
+    unsigned int register_index;
+    /** Shader stage(s) to which the resource is visible. */
+    enum vkd3d_shader_visibility shader_visibility;
+    /** A combination of zero or more elements of vkd3d_shader_binding_flag. */
+    unsigned int flags;
+
+    /** The binding in the target environment. */
+    struct vkd3d_shader_descriptor_binding binding;
+};
+
+#define VKD3D_SHADER_DUMMY_SAMPLER_INDEX ~0u
+
+/**
+ * Describes the mapping of a Direct3D resource-sampler pair to a combined
+ * sampler (i.e. sampled image).
+ *
+ * This structure is used in struct vkd3d_shader_interface_info.
+ */
+struct vkd3d_shader_combined_resource_sampler
+{
+    /**
+     * Register space of the Direct3D resource. If the source format does not
+     * support multiple register spaces, this parameter must be set to 0.
+     */
+    unsigned int resource_space;
+    /** Register index of the Direct3D resource. */
+    unsigned int resource_index;
+    /**
+     * Register space of the Direct3D sampler. If the source format does not
+     * support multiple register spaces, this parameter must be set to 0.
+     */
+    unsigned int sampler_space;
+    /** Register index of the Direct3D sampler. */
+    unsigned int sampler_index;
+    /** Shader stage(s) to which the resource is visible. */
+    enum vkd3d_shader_visibility shader_visibility;
+    /** A combination of zero or more elements of vkd3d_shader_binding_flag. */
+    unsigned int flags;
+
+    /** The binding in the target environment. */
+    struct vkd3d_shader_descriptor_binding binding;
+};
+
+/**
+ * Describes the mapping of a single Direct3D UAV counter.
+ *
+ * This structure is used in struct vkd3d_shader_interface_info.
+ */
+struct vkd3d_shader_uav_counter_binding
+{
+    /**
+     * Register space of the Direct3D UAV descriptor. If the source format does
+     * not support multiple register spaces, this parameter must be set to 0.
+     */
+    unsigned int register_space;
+    /** Register index of the Direct3D UAV descriptor. */
+    unsigned int register_index;
+    /** Shader stage(s) to which the UAV counter is visible. */
+    enum vkd3d_shader_visibility shader_visibility;
+
+    /** The binding in the target environment. */
+    struct vkd3d_shader_descriptor_binding binding;
+    unsigned int offset;
+};
+
+/**
+ * Describes the mapping of a Direct3D constant buffer to a range of push
+ * constants in the target environment.
+ *
+ * This structure is used in struct vkd3d_shader_interface_info.
+ */
+struct vkd3d_shader_push_constant_buffer
+{
+    /**
+     * Register space of the Direct3D resource. If the source format does not
+     * support multiple register spaces, this parameter must be set to 0.
+     */
+    unsigned int register_space;
+    /** Register index of the Direct3D resource. */
+    unsigned int register_index;
+    /** Shader stage(s) to which the resource is visible. */
+    enum vkd3d_shader_visibility shader_visibility;
+
+    /** Offset, in bytes, of the target push constants. */
+    unsigned int offset;
+    /** Size, in bytes, of the target push constants. */
+    unsigned int size;
+};
+
+/**
+ * A chained structure describing the interface between a compiled shader and
+ * the target environment.
+ *
+ * For example, when compiling Direct3D shader byte code to SPIR-V, this
+ * structure contains mappings from Direct3D descriptor registers to SPIR-V
+ * descriptor bindings.
+ *
+ * This structure is optional. If omitted, vkd3d_shader_compile() will use a
+ * default mapping, in which resources are mapped to sequential bindings in
+ * register set 0.
+ *
+ * This structure extends vkd3d_shader_compile_info.
+ *
+ * This structure contains only input parameters.
+ */
+struct vkd3d_shader_interface_info
+{
+    /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO. */
+    enum vkd3d_shader_structure_type type;
+    /** Optional pointer to a structure containing further parameters. */
+    const void *next;
+
+    /** Pointer to an array of bindings for shader resource descriptors. */
+    const struct vkd3d_shader_resource_binding *bindings;
+    /** Size, in elements, of \ref bindings. */
+    unsigned int binding_count;
+
+    /** Pointer to an array of bindings for push constant buffers. */
+    const struct vkd3d_shader_push_constant_buffer *push_constant_buffers;
+    /** Size, in elements, of \ref push_constant_buffers. */
+    unsigned int push_constant_buffer_count;
+
+    /** Pointer to an array of bindings for combined samplers. */
+    const struct vkd3d_shader_combined_resource_sampler *combined_samplers;
+    /** Size, in elements, of \ref combined_samplers. */
+    unsigned int combined_sampler_count;
+
+    /** Pointer to an array of bindings for UAV counters. */
+    const struct vkd3d_shader_uav_counter_binding *uav_counters;
+    /** Size, in elements, of \ref uav_counters. */
+    unsigned int uav_counter_count;
+};
+
+struct vkd3d_shader_transform_feedback_element
+{
+    unsigned int stream_index;
+    const char *semantic_name;
+    unsigned int semantic_index;
+    uint8_t component_index;
+    uint8_t component_count;
+    uint8_t output_slot;
+};
+
+/* Extends vkd3d_shader_interface_info. */
+struct vkd3d_shader_transform_feedback_info
+{
+    enum vkd3d_shader_structure_type type;
+    const void *next;
+
+    const struct vkd3d_shader_transform_feedback_element *elements;
+    unsigned int element_count;
+    const unsigned int *buffer_strides;
+    unsigned int buffer_stride_count;
+};
+
+/** The format of a shader to be compiled or scanned. */
+enum vkd3d_shader_source_type
+{
+    /**
+     * The shader has no type or is to be ignored. This is not a valid value
+     * for vkd3d_shader_compile() or vkd3d_shader_scan().
+     */
+    VKD3D_SHADER_SOURCE_NONE,
+    /**
+     * A 'Tokenized Program Format' shader embedded in a DXBC container. This is
+     * the format used for Direct3D shader model 4 and 5 shaders.
+     */
+    VKD3D_SHADER_SOURCE_DXBC_TPF,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SOURCE_TYPE),
+};
+
+/** The output format of a compiled shader. */
+enum vkd3d_shader_target_type
+{
+    /**
+     * The shader has no type or is to be ignored. This is not a valid value
+     * for vkd3d_shader_compile() or vkd3d_shader_scan().
+     */
+    VKD3D_SHADER_TARGET_NONE,
+    /**
+     * A SPIR-V shader in binary form. This is the format used for Vulkan
+     * shaders.
+     */
+    VKD3D_SHADER_TARGET_SPIRV_BINARY,
+    VKD3D_SHADER_TARGET_SPIRV_TEXT,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE),
+};
+
+/**
+ * Describes the minimum severity of compilation messages returned by
+ * vkd3d_shader_compile() and similar functions.
+ */
+enum vkd3d_shader_log_level
+{
+    /** No messages will be returned. */
+    VKD3D_SHADER_LOG_NONE,
+    /** Only fatal errors which prevent successful compilation will be returned. */
+    VKD3D_SHADER_LOG_ERROR,
+    /** Non-fatal warnings and fatal errors will be returned. */
+    VKD3D_SHADER_LOG_WARNING,
+    /**
+     * All messages, including general informational messages, will be returned.
+     */
+    VKD3D_SHADER_LOG_INFO,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_LOG_LEVEL),
+};
+
+/**
+ * A chained structure containing compilation parameters.
+ */
+struct vkd3d_shader_compile_info
+{
+    /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO. */
+    enum vkd3d_shader_structure_type type;
+    /**
+     * Optional pointer to a structure containing further parameters. For a list
+     * of valid structures, refer to the respective function documentation. If
+     * no further parameters are needed, this field should be set to NULL.
+     */
+    const void *next;
+
+    /** Input source code or byte code. */
+    struct vkd3d_shader_code source;
+
+    /** Format of the input code passed in \ref source. */
+    enum vkd3d_shader_source_type source_type;
+    /** Desired output format. */
+    enum vkd3d_shader_target_type target_type;
+
+    /**
+     * Pointer to an array of compilation options. This field is ignored if
+     * \ref option_count is zero, but must be valid otherwise.
+     *
+     * If the same option is specified multiple times, only the last value is
+     * used.
+     *
+     * Options not relevant to or not supported by a particular shader compiler
+     * or scanner will be ignored.
+     */
+    const struct vkd3d_shader_compile_option *options;
+    /** Size, in elements, of \ref options. */
+    unsigned int option_count;
+
+    /** Minimum severity of messages returned from the shader function. */
+    enum vkd3d_shader_log_level log_level;
+    /**
+     * Name of the initial source file, which may be used in error messages or
+     * debug information. This parameter is optional and may be NULL.
+     */
+    const char *source_name;
+};
+
+enum vkd3d_shader_spirv_environment
+{
+    VKD3D_SHADER_SPIRV_ENVIRONMENT_NONE,
+    VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5,
+    VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0, /* default target */
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_ENVIRONMENT),
+};
+
+enum vkd3d_shader_spirv_extension
+{
+    VKD3D_SHADER_SPIRV_EXTENSION_NONE,
+    VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_EXTENSION),
+};
+
+/* Extends vkd3d_shader_compile_info. */
+struct vkd3d_shader_spirv_target_info
+{
+    enum vkd3d_shader_structure_type type;
+    const void *next;
+
+    const char *entry_point; /* "main" if NULL. */
+
+    enum vkd3d_shader_spirv_environment environment;
+
+    const enum vkd3d_shader_spirv_extension *extensions;
+    unsigned int extension_count;
+
+    const struct vkd3d_shader_parameter *parameters;
+    unsigned int parameter_count;
+
+    bool dual_source_blending;
+    const unsigned int *output_swizzles;
+    unsigned int output_swizzle_count;
+};
+
+enum vkd3d_shader_tessellator_output_primitive
+{
+    VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT        = 0x1,
+    VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE         = 0x2,
+    VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW  = 0x3,
+    VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW = 0x4,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TESSELLATOR_OUTPUT_PRIMITIVE),
+};
+
+enum vkd3d_shader_tessellator_partitioning
+{
+    VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER         = 0x1,
+    VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2            = 0x2,
+    VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD  = 0x3,
+    VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 0x4,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TESSELLATOR_PARTITIONING),
+};
+
+/* Extends vkd3d_shader_spirv_target_info. */
+struct vkd3d_shader_spirv_domain_shader_target_info
+{
+    enum vkd3d_shader_structure_type type;
+    const void *next;
+
+    enum vkd3d_shader_tessellator_output_primitive output_primitive;
+    enum vkd3d_shader_tessellator_partitioning partitioning;
+};
+
+/* root signature 1.0 */
+enum vkd3d_shader_filter
+{
+    VKD3D_SHADER_FILTER_MIN_MAG_MIP_POINT                          = 0x000,
+    VKD3D_SHADER_FILTER_MIN_MAG_POINT_MIP_LINEAR                   = 0x001,
+    VKD3D_SHADER_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT             = 0x004,
+    VKD3D_SHADER_FILTER_MIN_POINT_MAG_MIP_LINEAR                   = 0x005,
+    VKD3D_SHADER_FILTER_MIN_LINEAR_MAG_MIP_POINT                   = 0x010,
+    VKD3D_SHADER_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR            = 0x011,
+    VKD3D_SHADER_FILTER_MIN_MAG_LINEAR_MIP_POINT                   = 0x014,
+    VKD3D_SHADER_FILTER_MIN_MAG_MIP_LINEAR                         = 0x015,
+    VKD3D_SHADER_FILTER_ANISOTROPIC                                = 0x055,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_MAG_MIP_POINT               = 0x080,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR        = 0x081,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT  = 0x084,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR        = 0x085,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT        = 0x090,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x091,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT        = 0x094,
+    VKD3D_SHADER_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR              = 0x095,
+    VKD3D_SHADER_FILTER_COMPARISON_ANISOTROPIC                     = 0x0d5,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_MAG_MIP_POINT                  = 0x100,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR           = 0x101,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT     = 0x104,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR           = 0x105,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT           = 0x110,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR    = 0x111,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT           = 0x114,
+    VKD3D_SHADER_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR                 = 0x115,
+    VKD3D_SHADER_FILTER_MINIMUM_ANISOTROPIC                        = 0x155,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_MAG_MIP_POINT                  = 0x180,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR           = 0x181,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT     = 0x184,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR           = 0x185,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT           = 0x190,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR    = 0x191,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT           = 0x194,
+    VKD3D_SHADER_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR                 = 0x195,
+    VKD3D_SHADER_FILTER_MAXIMUM_ANISOTROPIC                        = 0x1d5,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_FILTER),
+};
+
+enum vkd3d_shader_texture_address_mode
+{
+    VKD3D_SHADER_TEXTURE_ADDRESS_MODE_WRAP        = 0x1,
+    VKD3D_SHADER_TEXTURE_ADDRESS_MODE_MIRROR      = 0x2,
+    VKD3D_SHADER_TEXTURE_ADDRESS_MODE_CLAMP       = 0x3,
+    VKD3D_SHADER_TEXTURE_ADDRESS_MODE_BORDER      = 0x4,
+    VKD3D_SHADER_TEXTURE_ADDRESS_MODE_MIRROR_ONCE = 0x5,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TEXTURE_ADDRESS_MODE),
+};
+
+enum vkd3d_shader_comparison_func
+{
+    VKD3D_SHADER_COMPARISON_FUNC_NEVER         = 0x1,
+    VKD3D_SHADER_COMPARISON_FUNC_LESS          = 0x2,
+    VKD3D_SHADER_COMPARISON_FUNC_EQUAL         = 0x3,
+    VKD3D_SHADER_COMPARISON_FUNC_LESS_EQUAL    = 0x4,
+    VKD3D_SHADER_COMPARISON_FUNC_GREATER       = 0x5,
+    VKD3D_SHADER_COMPARISON_FUNC_NOT_EQUAL     = 0x6,
+    VKD3D_SHADER_COMPARISON_FUNC_GREATER_EQUAL = 0x7,
+    VKD3D_SHADER_COMPARISON_FUNC_ALWAYS        = 0x8,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPARISON_FUNC),
+};
+
+enum vkd3d_shader_static_border_colour
+{
+    VKD3D_SHADER_STATIC_BORDER_COLOUR_TRANSPARENT_BLACK = 0x0,
+    VKD3D_SHADER_STATIC_BORDER_COLOUR_OPAQUE_BLACK      = 0x1,
+    VKD3D_SHADER_STATIC_BORDER_COLOUR_OPAQUE_WHITE      = 0x2,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STATIC_BORDER_COLOUR),
+};
+
+struct vkd3d_shader_static_sampler_desc
+{
+    enum vkd3d_shader_filter filter;
+    enum vkd3d_shader_texture_address_mode address_u;
+    enum vkd3d_shader_texture_address_mode address_v;
+    enum vkd3d_shader_texture_address_mode address_w;
+    float mip_lod_bias;
+    unsigned int max_anisotropy;
+    enum vkd3d_shader_comparison_func comparison_func;
+    enum vkd3d_shader_static_border_colour border_colour;
+    float min_lod;
+    float max_lod;
+    unsigned int shader_register;
+    unsigned int register_space;
+    enum vkd3d_shader_visibility shader_visibility;
+};
+
+struct vkd3d_shader_descriptor_range
+{
+    enum vkd3d_shader_descriptor_type range_type;
+    unsigned int descriptor_count;
+    unsigned int base_shader_register;
+    unsigned int register_space;
+    unsigned int descriptor_table_offset;
+};
+
+struct vkd3d_shader_root_descriptor_table
+{
+    unsigned int descriptor_range_count;
+    const struct vkd3d_shader_descriptor_range *descriptor_ranges;
+};
+
+struct vkd3d_shader_root_constants
+{
+    unsigned int shader_register;
+    unsigned int register_space;
+    unsigned int value_count;
+};
+
+struct vkd3d_shader_root_descriptor
+{
+    unsigned int shader_register;
+    unsigned int register_space;
+};
+
+enum vkd3d_shader_root_parameter_type
+{
+    VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE = 0x0,
+    VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS  = 0x1,
+    VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV              = 0x2,
+    VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV              = 0x3,
+    VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV              = 0x4,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_ROOT_PARAMETER_TYPE),
+};
+
+struct vkd3d_shader_root_parameter
+{
+    enum vkd3d_shader_root_parameter_type parameter_type;
+    union
+    {
+        struct vkd3d_shader_root_descriptor_table descriptor_table;
+        struct vkd3d_shader_root_constants constants;
+        struct vkd3d_shader_root_descriptor descriptor;
+    } u;
+    enum vkd3d_shader_visibility shader_visibility;
+};
+
+enum vkd3d_shader_root_signature_flags
+{
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_NONE                               = 0x00,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x01,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS     = 0x02,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS       = 0x04,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS     = 0x08,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS   = 0x10,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS      = 0x20,
+    VKD3D_SHADER_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT                = 0x40,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_ROOT_SIGNATURE_FLAGS),
+};
+
+struct vkd3d_shader_root_signature_desc
+{
+    unsigned int parameter_count;
+    const struct vkd3d_shader_root_parameter *parameters;
+    unsigned int static_sampler_count;
+    const struct vkd3d_shader_static_sampler_desc *static_samplers;
+    enum vkd3d_shader_root_signature_flags flags;
+};
+
+/* root signature 1.1 */
+enum vkd3d_shader_root_descriptor_flags
+{
+    VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_NONE                             = 0x0,
+    VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE                    = 0x2,
+    VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_STATIC                      = 0x8,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_ROOT_DESCRIPTOR_FLAGS),
+};
+
+enum vkd3d_shader_descriptor_range_flags
+{
+    VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_NONE                             = 0x0,
+    VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE             = 0x1,
+    VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE                    = 0x2,
+    VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
+    VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC                      = 0x8,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_RANGE_FLAGS),
+};
+
+struct vkd3d_shader_descriptor_range1
+{
+    enum vkd3d_shader_descriptor_type range_type;
+    unsigned int descriptor_count;
+    unsigned int base_shader_register;
+    unsigned int register_space;
+    enum vkd3d_shader_descriptor_range_flags flags;
+    unsigned int descriptor_table_offset;
+};
+
+struct vkd3d_shader_root_descriptor_table1
+{
+    unsigned int descriptor_range_count;
+    const struct vkd3d_shader_descriptor_range1 *descriptor_ranges;
+};
+
+struct vkd3d_shader_root_descriptor1
+{
+    unsigned int shader_register;
+    unsigned int register_space;
+    enum vkd3d_shader_root_descriptor_flags flags;
+};
+
+struct vkd3d_shader_root_parameter1
+{
+    enum vkd3d_shader_root_parameter_type parameter_type;
+    union
+    {
+        struct vkd3d_shader_root_descriptor_table1 descriptor_table;
+        struct vkd3d_shader_root_constants constants;
+        struct vkd3d_shader_root_descriptor1 descriptor;
+    } u;
+    enum vkd3d_shader_visibility shader_visibility;
+};
+
+struct vkd3d_shader_root_signature_desc1
+{
+    unsigned int parameter_count;
+    const struct vkd3d_shader_root_parameter1 *parameters;
+    unsigned int static_sampler_count;
+    const struct vkd3d_shader_static_sampler_desc *static_samplers;
+    enum vkd3d_shader_root_signature_flags flags;
+};
+
+enum vkd3d_shader_root_signature_version
+{
+    VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0 = 0x1,
+    VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1 = 0x2,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_ROOT_SIGNATURE_VERSION),
+};
+
+struct vkd3d_shader_versioned_root_signature_desc
+{
+    enum vkd3d_shader_root_signature_version version;
+    union
+    {
+        struct vkd3d_shader_root_signature_desc v_1_0;
+        struct vkd3d_shader_root_signature_desc1 v_1_1;
+    } u;
+};
+
+/**
+ * The type of a shader resource, returned as part of struct
+ * vkd3d_shader_descriptor_info.
+ */
+enum vkd3d_shader_resource_type
+{
+    /**
+     * The type is invalid or not applicable for this descriptor. This value is
+     * returned for samplers.
+     */
+    VKD3D_SHADER_RESOURCE_NONE              = 0x0,
+    /** Dimensionless buffer. */
+    VKD3D_SHADER_RESOURCE_BUFFER            = 0x1,
+    /** 1-dimensional texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_1D        = 0x2,
+    /** 2-dimensional texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_2D        = 0x3,
+    /** Multisampled 2-dimensional texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_2DMS      = 0x4,
+    /** 3-dimensional texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_3D        = 0x5,
+    /** Cubemap texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_CUBE      = 0x6,
+    /** 1-dimensional array texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY   = 0x7,
+    /** 2-dimensional array texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY   = 0x8,
+    /** Multisampled 2-dimensional array texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY = 0x9,
+    /** Cubemap array texture. */
+    VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY = 0xa,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_RESOURCE_TYPE),
+};
+
+/**
+ * The type of the data contained in a shader resource, returned as part of
+ * struct vkd3d_shader_descriptor_info. All formats are 32-bit.
+ */
+enum vkd3d_shader_resource_data_type
+{
+    /** Unsigned normalized integer. */
+    VKD3D_SHADER_RESOURCE_DATA_UNORM = 0x1,
+    /** Signed normalized integer. */
+    VKD3D_SHADER_RESOURCE_DATA_SNORM = 0x2,
+    /** Signed integer. */
+    VKD3D_SHADER_RESOURCE_DATA_INT   = 0x3,
+    /** Unsigned integer. */
+    VKD3D_SHADER_RESOURCE_DATA_UINT  = 0x4,
+    /** IEEE floating-point. */
+    VKD3D_SHADER_RESOURCE_DATA_FLOAT = 0x5,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_RESOURCE_DATA_TYPE),
+};
+
+/**
+ * Additional flags describing a shader descriptor, returned as part of struct
+ * vkd3d_shader_descriptor_info.
+ */
+enum vkd3d_shader_descriptor_info_flag
+{
+    /**
+     * The descriptor is a UAV resource, whose counter is read from or written
+     * to by the shader.
+     */
+    VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER             = 0x00000001,
+    /** The descriptor is a UAV resource, which is read from by the shader. */
+    VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ                = 0x00000002,
+    /** The descriptor is a comparison sampler. */
+    VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE = 0x00000004,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_INFO_FLAG),
+};
+
+/**
+ * Describes a single shader descriptor; returned as part of
+ * struct vkd3d_shader_scan_descriptor_info.
+ */
+struct vkd3d_shader_descriptor_info
+{
+    /** Type of the descriptor (for example, SRV, CBV, UAV, or sampler). */
+    enum vkd3d_shader_descriptor_type type;
+    /**
+     * Register space of the resource, or 0 if the shader does not
+     * support multiple register spaces.
+     */
+    unsigned int register_space;
+    /** Register index of the descriptor. */
+    unsigned int register_index;
+    /** Resource type, if applicable, including its dimension. */
+    enum vkd3d_shader_resource_type resource_type;
+    /** Data type contained in the resource (for example, float or integer). */
+    enum vkd3d_shader_resource_data_type resource_data_type;
+    /**
+     * Bitwise combination of zero or more members of
+     * \ref vkd3d_shader_descriptor_info_flag.
+     */
+    unsigned int flags;
+    /** Size of this descriptor array, or 1 if a single descriptor. */
+    unsigned int count;
+};
+
+/**
+ * A chained structure enumerating the descriptors declared by a shader.
+ *
+ * This structure extends vkd3d_shader_compile_info.
+ */
+struct vkd3d_shader_scan_descriptor_info
+{
+    /**
+     * Input; must be set to VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO.
+     */
+    enum vkd3d_shader_structure_type type;
+    /** Input; optional pointer to a structure containing further parameters. */
+    const void *next;
+
+    /** Output; returns a pointer to an array of descriptors. */
+    struct vkd3d_shader_descriptor_info *descriptors;
+    /** Output; size, in elements, of \ref descriptors. */
+    unsigned int descriptor_count;
+};
+
+/**
+ * Data type of a shader varying, returned as part of struct
+ * vkd3d_shader_signature_element.
+ */
+enum vkd3d_shader_component_type
+{
+    /** The varying has no type. */
+    VKD3D_SHADER_COMPONENT_VOID     = 0x0,
+    /** 32-bit unsigned integer. */
+    VKD3D_SHADER_COMPONENT_UINT     = 0x1,
+    /** 32-bit signed integer. */
+    VKD3D_SHADER_COMPONENT_INT      = 0x2,
+    /** 32-bit IEEE floating-point. */
+    VKD3D_SHADER_COMPONENT_FLOAT    = 0x3,
+    /** Boolean. */
+    VKD3D_SHADER_COMPONENT_BOOL     = 0x4,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPONENT_TYPE),
+};
+
+/** System value semantic, returned as part of struct vkd3d_shader_signature. */
+enum vkd3d_shader_sysval_semantic
+{
+    /** No system value. */
+    VKD3D_SHADER_SV_NONE                      = 0x00,
+    /** Vertex position; SV_Position in Direct3D. */
+    VKD3D_SHADER_SV_POSITION                  = 0x01,
+    /** Clip distance; SV_ClipDistance in Direct3D. */
+    VKD3D_SHADER_SV_CLIP_DISTANCE             = 0x02,
+    /** Cull distance; SV_CullDistance in Direct3D. */
+    VKD3D_SHADER_SV_CULL_DISTANCE             = 0x03,
+    /** Render target layer; SV_RenderTargetArrayIndex in Direct3D. */
+    VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX = 0x04,
+    /** Viewport index; SV_ViewportArrayIndex in Direct3D. */
+    VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX      = 0x05,
+    /** Vertex ID; SV_VertexID in Direct3D. */
+    VKD3D_SHADER_SV_VERTEX_ID                 = 0x06,
+    /** Primtive ID; SV_PrimitiveID in Direct3D. */
+    VKD3D_SHADER_SV_PRIMITIVE_ID              = 0x07,
+    /** Instance ID; SV_InstanceID in Direct3D. */
+    VKD3D_SHADER_SV_INSTANCE_ID               = 0x08,
+    /** Whether the triangle is front-facing; SV_IsFrontFace in Direct3D. */
+    VKD3D_SHADER_SV_IS_FRONT_FACE             = 0x09,
+    /** Sample index; SV_SampleIndex in Direct3D. */
+    VKD3D_SHADER_SV_SAMPLE_INDEX              = 0x0a,
+    VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE      = 0x0b,
+    VKD3D_SHADER_SV_TESS_FACTOR_QUADINT       = 0x0c,
+    VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE       = 0x0d,
+    VKD3D_SHADER_SV_TESS_FACTOR_TRIINT        = 0x0e,
+    VKD3D_SHADER_SV_TESS_FACTOR_LINEDET       = 0x0f,
+    VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN       = 0x10,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SYSVAL_SEMANTIC),
+};
+
+/**
+ * Minimum interpolation precision of a shader varying, returned as part of
+ * struct vkd3d_shader_signature_element.
+ */
+enum vkd3d_shader_minimum_precision
+{
+    VKD3D_SHADER_MINIMUM_PRECISION_NONE      = 0,
+    /** 16-bit floating-point. */
+    VKD3D_SHADER_MINIMUM_PRECISION_FLOAT_16  = 1,
+    /** 10-bit fixed point (2 integer and 8 fractional bits). */
+    VKD3D_SHADER_MINIMUM_PRECISION_FIXED_8_2 = 2,
+    /** 16-bit signed integer. */
+    VKD3D_SHADER_MINIMUM_PRECISION_INT_16    = 4,
+    /** 16-bit unsigned integer. */
+    VKD3D_SHADER_MINIMUM_PRECISION_UINT_16   = 5,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_MINIMUM_PRECISION),
+};
+
+/**
+ * A single shader varying, returned as part of struct vkd3d_shader_signature.
+ */
+struct vkd3d_shader_signature_element
+{
+    /** Semantic name. */
+    const char *semantic_name;
+    /** Semantic index, or 0 if the semantic is not indexed. */
+    unsigned int semantic_index;
+    /**
+     * Stream index of a geometry shader output semantic. If the signature is
+     * not a geometry shader output signature, this field will be set to 0.
+     */
+    unsigned int stream_index;
+    /**
+     * System value semantic. If the varying is not a system value, this field
+     * will be set to VKD3D_SHADER_SV_NONE.
+     */
+    enum vkd3d_shader_sysval_semantic sysval_semantic;
+    /** Data type. */
+    enum vkd3d_shader_component_type component_type;
+    /** Register index. */
+    unsigned int register_index;
+    /** Mask of the register components allocated to this varying. */
+    unsigned int mask;
+    /**
+     * Subset of \ref mask which the shader reads from or writes to. Unlike
+     * Direct3D shader bytecode, the mask for output and tessellation signatures
+     * is not inverted, i.e. bits set in this field denote components which are
+     * written to.
+     */
+    unsigned int used_mask;
+    /** Minimum interpolation precision. */
+    enum vkd3d_shader_minimum_precision min_precision;
+};
+
+/**
+ * Description of a shader input or output signature. This structure is
+ * populated by vkd3d_shader_parse_input_signature().
+ *
+ * The helper function vkd3d_shader_find_signature_element() will look up a
+ * varying element by its semantic name, semantic index, and stream index.
+ */
+struct vkd3d_shader_signature
+{
+    /** Pointer to an array of varyings. */
+    struct vkd3d_shader_signature_element *elements;
+    /** Size, in elements, of \ref elements. */
+    unsigned int element_count;
+};
+
+/** Possible values for a single component of a vkd3d-shader swizzle. */
+enum vkd3d_shader_swizzle_component
+{
+    VKD3D_SHADER_SWIZZLE_X = 0x0,
+    VKD3D_SHADER_SWIZZLE_Y = 0x1,
+    VKD3D_SHADER_SWIZZLE_Z = 0x2,
+    VKD3D_SHADER_SWIZZLE_W = 0x3,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SWIZZLE_COMPONENT),
+};
+
+/**
+ * A mask selecting one component from a vkd3d-shader swizzle. The component has
+ * type \ref vkd3d_shader_swizzle_component.
+ */
+#define VKD3D_SHADER_SWIZZLE_MASK (0xffu)
+/** The offset, in bits, of the nth parameter of a vkd3d-shader swizzle. */
+#define VKD3D_SHADER_SWIZZLE_SHIFT(idx) (8u * (idx))
+
+/**
+ * A helper macro which returns a vkd3d-shader swizzle with the given
+ * components. The components are specified as the suffixes to members of
+ * \ref vkd3d_shader_swizzle_component. For example, the swizzle ".xwyy" can be
+ * represented as:
+ * \code
+ * VKD3D_SHADER_SWIZZLE(X, W, Y, Y)
+ * \endcode
+ */
+#define VKD3D_SHADER_SWIZZLE(x, y, z, w) \
+        vkd3d_shader_create_swizzle(VKD3D_SHADER_SWIZZLE_ ## x, \
+                VKD3D_SHADER_SWIZZLE_ ## y, \
+                VKD3D_SHADER_SWIZZLE_ ## z, \
+                VKD3D_SHADER_SWIZZLE_ ## w)
+
+/** The identity swizzle ".xyzw". */
+#define VKD3D_SHADER_NO_SWIZZLE VKD3D_SHADER_SWIZZLE(X, Y, Z, W)
+
+/** Build a vkd3d-shader swizzle with the given components. */
+static inline uint32_t vkd3d_shader_create_swizzle(enum vkd3d_shader_swizzle_component x,
+        enum vkd3d_shader_swizzle_component y, enum vkd3d_shader_swizzle_component z,
+        enum vkd3d_shader_swizzle_component w)
+{
+    return ((x & VKD3D_SHADER_SWIZZLE_MASK) << VKD3D_SHADER_SWIZZLE_SHIFT(0))
+            | ((y & VKD3D_SHADER_SWIZZLE_MASK) << VKD3D_SHADER_SWIZZLE_SHIFT(1))
+            | ((z & VKD3D_SHADER_SWIZZLE_MASK) << VKD3D_SHADER_SWIZZLE_SHIFT(2))
+            | ((w & VKD3D_SHADER_SWIZZLE_MASK) << VKD3D_SHADER_SWIZZLE_SHIFT(3));
+}
+
+#ifndef VKD3D_SHADER_NO_PROTOTYPES
+
+/**
+ * Returns the current version of this library.
+ *
+ * \param major Output location for the major version of this library.
+ *
+ * \param minor Output location for the minor version of this library.
+ *
+ * \return A human-readable string describing the library name and version. This
+ * string is null-terminated and UTF-8 encoded. This may be a pointer to static
+ * data in libvkd3d-shader; it should not be freed.
+ */
+const char *vkd3d_shader_get_version(unsigned int *major, unsigned int *minor);
+/**
+ * Returns the source types supported, with any target type, by
+ * vkd3d_shader_compile().
+ *
+ * Use vkd3d_shader_get_supported_target_types() to determine which target types
+ * are supported for each source type.
+ *
+ * \param count Output location for the size, in elements, of the returned
+ * array.
+ *
+ * \return Pointer to an array of source types supported by this version of
+ * vkd3d-shader. This array may be a pointer to static data in libvkd3d-shader;
+ * it should not be freed.
+ */
+const enum vkd3d_shader_source_type *vkd3d_shader_get_supported_source_types(unsigned int *count);
+/**
+ * Returns the target types supported, with the given source type, by
+ * vkd3d_shader_compile().
+ *
+ * \param source_type Source type for which to enumerate supported target types.
+ *
+ * \param count Output location for the size, in elements, of the returned
+ * array.
+ *
+ * \return Pointer to an array of target types supported by this version of
+ * vkd3d-shader. This array may be a pointer to static data in libvkd3d-shader;
+ * it should not be freed.
+ */
+const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types(
+        enum vkd3d_shader_source_type source_type, unsigned int *count);
+
+/**
+ * Transform a form of GPU shader source code or byte code into another form of
+ * source code or byte code.
+ *
+ * This version of vkd3d-shader supports the following transformations:
+ * - VKD3D_SHADER_SOURCE_DXBC_TPF to VKD3D_SHADER_TARGET_SPIRV_BINARY
+ *
+ * Supported transformations can also be detected at runtime with the functions
+ * vkd3d_shader_get_supported_source_types() and
+ * vkd3d_shader_get_supported_target_types().
+ *
+ * Depending on the source and target types, this function may support the
+ * following chained structures:
+ * - vkd3d_shader_interface_info
+ * - vkd3d_shader_spirv_domain_shader_target_info
+ * - vkd3d_shader_spirv_target_info
+ * - vkd3d_shader_transform_feedback_info
+ *
+ * \param compile_info A chained structure containing compilation parameters.
+ *
+ * \param out A pointer to a vkd3d_shader_code structure in which the compiled
+ * code will be stored.
+ * \n
+ * The compiled shader is allocated by vkd3d-shader and should be freed with
+ * vkd3d_shader_free_shader_code() when no longer needed.
+ *
+ * \param messages Optional output location for error or informational messages
+ * produced by the compiler.
+ * \n
+ * This string is null-terminated and UTF-8 encoded.
+ * \n
+ * The messages are allocated by vkd3d-shader and should be freed with
+ * vkd3d_shader_free_messages() when no longer needed.
+ * \n
+ * The messages returned can be regulated with the \a log_level member of struct
+ * vkd3d_shader_compile_info. Regardless of the requested level, if this
+ * parameter is NULL, no compilation messages will be returned.
+ * \n
+ * If no compilation messages are produced by the compiler, this parameter may
+ * receive NULL instead of a valid string pointer.
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
+        struct vkd3d_shader_code *out, char **messages);
+/**
+ * Free shader messages allocated by another vkd3d-shader function, such as
+ * vkd3d_shader_compile().
+ *
+ * \param messages Messages to free. This pointer is optional and may be NULL,
+ * in which case no action will be taken.
+ */
+void vkd3d_shader_free_messages(char *messages);
+/**
+ * Free shader code allocated by another vkd3d-shader function, such as
+ * vkd3d_shader_compile().
+ *
+ * This function frees the \ref vkd3d_shader_code.code member, but does not free
+ * the structure itself.
+ *
+ * \param code Code to free.
+ */
+void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *code);
+
+/**
+ * Convert a byte code description of a shader root signature to a structural
+ * description which can be easily parsed by C code.
+ *
+ * This function corresponds to
+ * ID3D12VersionedRootSignatureDeserializer::GetUnconvertedRootSignatureDesc().
+ *
+ * This function performs the reverse transformation of
+ * vkd3d_shader_serialize_root_signature().
+ *
+ * This function parses a standalone root signature, and should not be confused
+ * with vkd3d_shader_parse_input_signature().
+ *
+ * \param dxbc Compiled byte code, in DXBC format.
+ *
+ * \param root_signature Output location in which the decompiled root signature
+ * will be stored.
+ * \n
+ * Members of \a root_signature may be allocated by vkd3d-shader. The signature
+ * should be freed with vkd3d_shader_free_root_signature() when no longer
+ * needed.
+ *
+ * \param messages Optional output location for error or informational messages
+ * produced by the compiler.
+ * \n
+ * This parameter behaves identically to the \a messages parameter of
+ * vkd3d_shader_compile().
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_parse_root_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_versioned_root_signature_desc *root_signature, char **messages);
+/**
+ * Free a structural representation of a shader root signature allocated by
+ * vkd3d_shader_convert_root_signature() or vkd3d_shader_parse_root_signature().
+ *
+ * This function may free members of struct
+ * vkd3d_shader_versioned_root_signature_desc, but does not free the structure
+ * itself.
+ *
+ * \param root_signature Signature description to free.
+ */
+void vkd3d_shader_free_root_signature(struct vkd3d_shader_versioned_root_signature_desc *root_signature);
+
+/**
+ * Convert a structural description of a shader root signature to a byte code
+ * format capable of being read by ID3D12Device::CreateRootSignature. The
+ * compiled signature is compatible with Microsoft D3D 12.
+ *
+ * This function corresponds to D3D12SerializeVersionedRootSignature().
+ *
+ * \param root_signature Description of the root signature.
+ *
+ * \param dxbc A pointer to a vkd3d_shader_code structure in which the compiled
+ * code will be stored.
+ * \n
+ * The compiled signature is allocated by vkd3d-shader and should be freed with
+ * vkd3d_shader_free_shader_code() when no longer needed.
+ *
+ * \param messages Optional output location for error or informational messages
+ * produced by the compiler.
+ * \n
+ * This parameter behaves identically to the \a messages parameter of
+ * vkd3d_shader_compile().
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_root_signature_desc *root_signature,
+        struct vkd3d_shader_code *dxbc, char **messages);
+/**
+ * Convert a structural representation of a root signature to a different
+ * version of structural representation.
+ *
+ * This function corresponds to
+ * ID3D12VersionedRootSignatureDeserializer::GetRootSignatureDescAtVersion().
+ *
+ * \param dst A pointer to a vkd3d_shader_versioned_root_signature_desc
+ * structure in which the converted signature will be stored.
+ * \n
+ * Members of \a dst may be allocated by vkd3d-shader. The signature should be
+ * freed with vkd3d_shader_free_root_signature() when no longer needed.
+ *
+ * \param version The desired version to convert \a src to. This version must
+ * not be equal to \a src->version.
+ *
+ * \param src Input root signature description.
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_convert_root_signature(struct vkd3d_shader_versioned_root_signature_desc *dst,
+        enum vkd3d_shader_root_signature_version version, const struct vkd3d_shader_versioned_root_signature_desc *src);
+
+/**
+ * Parse shader source code or byte code, returning various types of requested
+ * information.
+ *
+ * Currently this function supports the following code types:
+ * - VKD3D_SHADER_SOURCE_DXBC_TPF
+ *
+ * \param compile_info A chained structure containing scan parameters.
+ * \n
+ * The DXBC_TPF scanner supports the following chained structures:
+ * - vkd3d_shader_scan_descriptor_info
+ * \n
+ * Although the \a compile_info parameter is read-only, chained structures
+ * passed to this function need not be, and may serve as output parameters,
+ * depending on their structure type.
+ *
+ * \param messages Optional output location for error or informational messages
+ * produced by the compiler.
+ * \n
+ * This parameter behaves identically to the \a messages parameter of
+ * vkd3d_shader_compile().
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages);
+/**
+ * Free members of struct vkd3d_shader_scan_descriptor_info() allocated by
+ * vkd3d_shader_scan().
+ *
+ * This function may free members of vkd3d_shader_scan_descriptor_info, but
+ * does not free the structure itself.
+ *
+ * \param scan_descriptor_info Descriptor information to free.
+ */
+void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info);
+
+/**
+ * Read the input signature of a compiled shader, returning a structural
+ * description which can be easily parsed by C code.
+ *
+ * This function parses a compiled shader. To parse a standalone root signature,
+ * use vkd3d_shader_parse_root_signature().
+ *
+ * \param dxbc Compiled byte code, in DXBC format.
+ *
+ * \param signature Output location in which the parsed root signature will be
+ * stored.
+ * \n
+ * Members of \a signature may be allocated by vkd3d-shader. The signature
+ * should be freed with vkd3d_shader_free_shader_signature() when no longer
+ * needed.
+ *
+ * \param messages Optional output location for error or informational messages
+ * produced by the compiler.
+ * \n
+ * This parameter behaves identically to the \a messages parameter of
+ * vkd3d_shader_compile().
+ *
+ * \return A member of \ref vkd3d_result.
+ */
+int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_signature *signature, char **messages);
+/**
+ * Find a single element of a parsed input signature.
+ *
+ * \param signature The parsed input signature. This structure is normally
+ * populated by vkd3d_shader_parse_input_signature().
+ *
+ * \param semantic_name Semantic name of the desired element. This function
+ * performs a case-insensitive comparison with respect to the ASCII plane.
+ *
+ * \param semantic_index Semantic index of the desired element.
+ *
+ * \param stream_index Geometry shader stream index of the desired element. If
+ * the signature is not a geometry shader output signature, this parameter must
+ * be set to 0.
+ *
+ * \return A description of the element matching the requested parameters, or
+ * NULL if no such element was found. If not NULL, the return value points into
+ * the \a signature parameter and should not be explicitly freed.
+ */
+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);
+/**
+ * Free a structural representation of a shader input signature allocated by
+ * vkd3d_shader_parse_input_signature().
+ *
+ * This function may free members of struct vkd3d_shader_signature, but does not
+ * free the structure itself.
+ *
+ * \param signature Signature description to free.
+ */
+void vkd3d_shader_free_shader_signature(struct vkd3d_shader_signature *signature);
+
+#endif  /* VKD3D_SHADER_NO_PROTOTYPES */
+
+/** Type of vkd3d_shader_get_version(). */
+typedef const char *(*PFN_vkd3d_shader_get_version)(unsigned int *major, unsigned int *minor);
+/** Type of vkd3d_shader_get_supported_source_types(). */
+typedef const enum vkd3d_shader_source_type *(*PFN_vkd3d_shader_get_supported_source_types)(unsigned int *count);
+/** Type of vkd3d_shader_get_supported_target_types(). */
+typedef const enum vkd3d_shader_target_type *(*PFN_vkd3d_shader_get_supported_target_types)(
+        enum vkd3d_shader_source_type source_type, unsigned int *count);
+
+/** Type of vkd3d_shader_compile(). */
+typedef int (*PFN_vkd3d_shader_compile)(const struct vkd3d_shader_compile_info *compile_info,
+        struct vkd3d_shader_code *out, char **messages);
+/** Type of vkd3d_shader_free_messages(). */
+typedef void (*PFN_vkd3d_shader_free_messages)(char *messages);
+/** Type of vkd3d_shader_free_shader_code(). */
+typedef void (*PFN_vkd3d_shader_free_shader_code)(struct vkd3d_shader_code *code);
+
+/** Type of vkd3d_shader_parse_root_signature(). */
+typedef int (*PFN_vkd3d_shader_parse_root_signature)(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_versioned_root_signature_desc *root_signature, char **messages);
+/** Type of vkd3d_shader_free_root_signature(). */
+typedef void (*PFN_vkd3d_shader_free_root_signature)(struct vkd3d_shader_versioned_root_signature_desc *root_signature);
+
+/** Type of vkd3d_shader_serialize_root_signature(). */
+typedef int (*PFN_vkd3d_shader_serialize_root_signature)(
+        const struct vkd3d_shader_versioned_root_signature_desc *root_signature,
+        struct vkd3d_shader_code *dxbc, char **messages);
+
+/** Type of vkd3d_shader_convert_root_signature(). */
+typedef int (*PFN_vkd3d_shader_convert_root_signature)(struct vkd3d_shader_versioned_root_signature_desc *dst,
+        enum vkd3d_shader_root_signature_version version, const struct vkd3d_shader_versioned_root_signature_desc *src);
+
+/** Type of vkd3d_shader_scan(). */
+typedef int (*PFN_vkd3d_shader_scan)(const struct vkd3d_shader_compile_info *compile_info, char **messages);
+/** Type of vkd3d_shader_free_scan_descriptor_info(). */
+typedef void (*PFN_vkd3d_shader_free_scan_descriptor_info)(
+        struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info);
+
+/** Type of vkd3d_shader_parse_input_signature(). */
+typedef int (*PFN_vkd3d_shader_parse_input_signature)(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_signature *signature, char **messages);
+/** Type of vkd3d_shader_find_signature_element(). */
+typedef struct vkd3d_shader_signature_element * (*PFN_vkd3d_shader_find_signature_element)(
+        const struct vkd3d_shader_signature *signature, const char *semantic_name,
+        unsigned int semantic_index, unsigned int stream_index);
+/** Type of vkd3d_shader_free_shader_signature(). */
+typedef void (*PFN_vkd3d_shader_free_shader_signature)(struct vkd3d_shader_signature *signature);
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+
+#endif  /* __VKD3D_SHADER_H */
diff --git a/dlls/vkd3d/include/vkd3d_types.h b/dlls/vkd3d/include/vkd3d_types.h
new file mode 100644
index 00000000000..020eb2400fb
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_types.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016-2018 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_TYPES_H
+#define __VKD3D_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+/**
+ * \file vkd3d_types.h
+ *
+ * This file contains definitions for basic types used by vkd3d libraries.
+ */
+
+#define VKD3D_FORCE_32_BIT_ENUM(name) name##_FORCE_32BIT = 0x7fffffff
+
+/**
+ * Result codes returned by some vkd3d functions. Error codes always have
+ * negative values; non-error codes never do.
+ */
+enum vkd3d_result
+{
+    /** Success. */
+    VKD3D_OK = 0,
+    /** An unspecified failure occurred. */
+    VKD3D_ERROR = -1,
+    /** There are not enough resources available to complete the operation. */
+    VKD3D_ERROR_OUT_OF_MEMORY = -2,
+    /** One or more parameters passed to a vkd3d function were invalid. */
+    VKD3D_ERROR_INVALID_ARGUMENT = -3,
+    /** A shader passed to a vkd3d function was invalid. */
+    VKD3D_ERROR_INVALID_SHADER = -4,
+    /** The operation is not implemented in this version of vkd3d. */
+    VKD3D_ERROR_NOT_IMPLEMENTED = -5,
+
+    VKD3D_FORCE_32_BIT_ENUM(VKD3D_RESULT),
+};
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+
+#endif  /* __VKD3D_TYPES_H */
diff --git a/dlls/vkd3d/include/vkd3d_unknown.idl b/dlls/vkd3d/include/vkd3d_unknown.idl
new file mode 100644
index 00000000000..9a7198c82d1
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_unknown.idl
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+cpp_quote("#ifndef __VKD3D_UNKNOWN_H")
+cpp_quote("#define __VKD3D_UNKNOWN_H")
+
+/* For IDL only. */
+cpp_quote("#if 0")
+typedef IID *REFIID;
+typedef IID *REFGUID;
+cpp_quote("#endif")
+
+cpp_quote("#if !defined(_WIN32)")
+typedef void *HWND;
+typedef void *HMODULE;
+
+typedef struct LUID
+{
+    DWORD LowPart;
+    LONG HighPart;
+} LUID;
+
+typedef struct _RECT
+{
+    LONG left;
+    LONG top;
+    LONG right;
+    LONG bottom;
+} RECT;
+cpp_quote("#endif")
+
+[uuid(00000000-0000-0000-C000-000000000046), object, local, pointer_default(unique)]
+interface IUnknown
+{
+    HRESULT QueryInterface(REFIID riid, void **object);
+    ULONG AddRef();
+    ULONG Release();
+}
+
+cpp_quote("#endif   /* __VKD3D_UNKNOWN_H */")
diff --git a/dlls/vkd3d/include/vkd3d_utils.h b/dlls/vkd3d/include/vkd3d_utils.h
new file mode 100644
index 00000000000..02687ed613f
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_UTILS_H
+#define __VKD3D_UTILS_H
+
+#include <vkd3d.h>
+
+#ifndef VKD3D_UTILS_API_VERSION
+#define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+#define VKD3D_WAIT_OBJECT_0 (0)
+#define VKD3D_WAIT_TIMEOUT (1)
+#define VKD3D_WAIT_FAILED (~0u)
+#define VKD3D_INFINITE (~0u)
+
+/* 1.0 */
+HANDLE vkd3d_create_event(void);
+HRESULT vkd3d_signal_event(HANDLE event);
+unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds);
+void vkd3d_destroy_event(HANDLE event);
+
+#define D3D12CreateDevice(a, b, c, d) D3D12CreateDeviceVKD3D(a, b, c, d, VKD3D_UTILS_API_VERSION)
+HRESULT WINAPI D3D12CreateRootSignatureDeserializer(const void *data, SIZE_T data_size, REFIID iid, void **deserializer);
+HRESULT WINAPI D3D12GetDebugInterface(REFIID iid, void **debug);
+HRESULT WINAPI D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
+
+/* 1.2 */
+HRESULT WINAPI D3D12CreateDeviceVKD3D(IUnknown *adapter, D3D_FEATURE_LEVEL feature_level,
+        REFIID iid, void **device, enum vkd3d_api_version api_version);
+HRESULT WINAPI D3D12CreateVersionedRootSignatureDeserializer(const void *data,
+        SIZE_T data_size, REFIID iid, void **deserializer);
+HRESULT WINAPI D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+        ID3DBlob **blob, ID3DBlob **error_blob);
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+
+#endif  /* __VKD3D_UTILS_H */
diff --git a/dlls/vkd3d/include/vkd3d_windows.h b/dlls/vkd3d/include/vkd3d_windows.h
new file mode 100644
index 00000000000..ad2f08a613a
--- /dev/null
+++ b/dlls/vkd3d/include/vkd3d_windows.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_WINDOWS_H
+#define __VKD3D_WINDOWS_H
+#ifndef _INC_WINDOWS
+
+/* Nameless unions */
+#ifndef __C89_NAMELESS
+# ifdef NONAMELESSUNION
+#  define __C89_NAMELESS
+#  define __C89_NAMELESSUNIONNAME u
+# else
+#  define __C89_NAMELESS
+#  define __C89_NAMELESSUNIONNAME
+# endif /* NONAMELESSUNION */
+#endif  /* __C89_NAMELESS */
+
+#if !defined(_WIN32) || defined(__WIDL__)
+
+# if !defined(__WIDL__)
+#  if !defined(VKD3D_WIN32_WCHAR)
+#   include <wchar.h>
+#  endif
+#  include <stdint.h>
+# endif
+
+# ifdef __GNUC__
+#  define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))
+# endif
+
+/* HRESULT */
+typedef int HRESULT;
+# define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+# define FAILED(hr)    ((HRESULT)(hr) < 0)
+
+# define _HRESULT_TYPEDEF_(x) ((HRESULT)x)
+
+# define S_OK    _HRESULT_TYPEDEF_(0)
+# define S_FALSE _HRESULT_TYPEDEF_(1)
+
+# define E_NOTIMPL     _HRESULT_TYPEDEF_(0x80004001)
+# define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002)
+# define E_POINTER     _HRESULT_TYPEDEF_(0x80004003)
+# define E_ABORT       _HRESULT_TYPEDEF_(0x80004004)
+# define E_FAIL        _HRESULT_TYPEDEF_(0x80004005)
+# define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000E)
+# define E_INVALIDARG  _HRESULT_TYPEDEF_(0x80070057)
+
+# define DXGI_ERROR_NOT_FOUND _HRESULT_TYPEDEF_(0x887a0002)
+# define DXGI_ERROR_MORE_DATA _HRESULT_TYPEDEF_(0x887a0003)
+
+/* Basic types */
+typedef unsigned char BYTE;
+typedef unsigned int DWORD;
+typedef int INT;
+typedef unsigned int UINT;
+typedef int LONG;
+typedef unsigned int ULONG;
+typedef float FLOAT;
+typedef LONG BOOL;
+
+/* Assuming LP64 model */
+typedef char INT8;
+typedef unsigned char UINT8;
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+# if defined(__WIDL__)
+typedef __int64 INT64;
+typedef unsigned __int64 UINT64;
+# else
+typedef int64_t DECLSPEC_ALIGN(8) INT64;
+typedef uint64_t DECLSPEC_ALIGN(8) UINT64;
+# endif
+typedef long LONG_PTR;
+typedef unsigned long ULONG_PTR;
+
+typedef ULONG_PTR SIZE_T;
+
+# ifdef VKD3D_WIN32_WCHAR
+typedef unsigned short WCHAR;
+# else
+typedef wchar_t WCHAR;
+# endif /* VKD3D_WIN32_WCHAR */
+typedef void *HANDLE;
+
+/* GUID */
+# ifdef __WIDL__
+typedef struct
+{
+    unsigned long Data1;
+    unsigned short Data2;
+    unsigned short Data3;
+    unsigned char Data4[8];
+} GUID;
+# else
+typedef struct _GUID
+{
+    unsigned int Data1;
+    unsigned short Data2;
+    unsigned short Data3;
+    unsigned char Data4[8];
+} GUID;
+# endif
+
+typedef GUID IID;
+
+# ifdef INITGUID
+#  ifndef __cplusplus
+#   define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+        const GUID name DECLSPEC_HIDDEN; \
+        const GUID name = \
+    { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 }}
+#  else
+#   define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+        EXTERN_C const GUID name DECLSPEC_HIDDEN; \
+        EXTERN_C const GUID name = \
+    { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 }}
+#  endif
+# else
+#  define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+        EXTERN_C const GUID name DECLSPEC_HIDDEN;
+# endif /* INITGUID */
+
+/* __uuidof emulation */
+#if defined(__cplusplus) && !defined(_MSC_VER)
+
+extern "C++"
+{
+    template<typename T> const GUID &__vkd3d_uuidof();
+}
+
+# define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+    extern "C++" \
+    { \
+        template<> inline const GUID &__vkd3d_uuidof<type>() \
+        { \
+            static const IID __uuid_inst = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}; \
+            return __uuid_inst; \
+        } \
+        template<> inline const GUID &__vkd3d_uuidof<type *>() \
+        { \
+            return __vkd3d_uuidof<type>(); \
+        } \
+    }
+
+# define __uuidof(type) __vkd3d_uuidof<typeof(type)>()
+#else
+# define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
+#endif /* defined(__cplusplus) && !defined(_MSC_VER) */
+
+typedef struct SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES;
+#endif  /* !defined(_WIN32) || defined(__WIDL__) */
+
+
+#ifndef _WIN32
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+
+# define COM_NO_WINDOWS_H
+
+# define FORCEINLINE inline
+
+# define CONTAINING_RECORD(address, type, field) \
+        ((type *)((char *)(address) - offsetof(type, field)))
+
+# ifdef __x86_64__
+#  define __stdcall __attribute__((ms_abi))
+# else
+#  if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__)
+#   define __stdcall __attribute__((__stdcall__)) __attribute__((__force_align_arg_pointer__))
+#  else
+#   define __stdcall __attribute__((__stdcall__))
+#  endif
+# endif
+
+# define WINAPI __stdcall
+# define STDMETHODCALLTYPE __stdcall
+
+# ifdef __GNUC__
+#  define DECLSPEC_SELECTANY __attribute__((weak))
+# endif
+
+/* Macros for COM interfaces */
+# define interface struct
+# define BEGIN_INTERFACE
+# define END_INTERFACE
+# define MIDL_INTERFACE(x) struct
+
+# ifdef __cplusplus
+#  define EXTERN_C extern "C"
+# else
+#  define EXTERN_C extern
+# endif
+
+# define CONST_VTBL const
+
+# define TRUE 1
+# define FALSE 0
+
+# if defined(__cplusplus) && !defined(CINTERFACE)
+#  define REFIID const IID &
+#  define REFGUID const GUID &
+# else
+#  define REFIID const IID * const
+#  define REFGUID const GUID * const
+# endif
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+# define IsEqualGUID(guid1, guid2) (!memcmp(&(guid1), &(guid2), sizeof(GUID)))
+#else
+# define IsEqualGUID(guid1, guid2) (!memcmp(guid1, guid2, sizeof(GUID)))
+#endif
+
+#elif !defined(__WIDL__)
+
+# include <windows.h>
+
+#endif  /* _WIN32 */
+
+
+/* Define DECLSPEC_HIDDEN */
+#ifndef DECLSPEC_HIDDEN
+# if defined(__MINGW32__)
+#  define DECLSPEC_HIDDEN
+# elif defined(__GNUC__)
+#  define DECLSPEC_HIDDEN __attribute__((visibility("hidden")))
+# else
+#  define DECLSPEC_HIDDEN
+# endif
+#endif  /* DECLSPEC_HIDDEN */
+
+/* Define min() & max() macros */
+#ifndef NOMINMAX
+# ifndef min
+#  define min(a, b) (((a) <= (b)) ? (a) : (b))
+# endif
+
+# ifndef max
+#  define max(a, b) (((a) >= (b)) ? (a) : (b))
+# endif
+#endif /* NOMINMAX */
+
+#ifndef DEFINE_ENUM_FLAG_OPERATORS
+#ifdef __cplusplus
+# define DEFINE_ENUM_FLAG_OPERATORS(type) \
+extern "C++" \
+{ \
+    inline type operator &(type x, type y) { return (type)((int)x & (int)y); } \
+    inline type operator &=(type &x, type y) { return (type &)((int &)x &= (int)y); } \
+    inline type operator ~(type x) { return (type)~(int)x; } \
+    inline type operator |(type x, type y) { return (type)((int)x | (int)y); } \
+    inline type operator |=(type &x, type y) { return (type &)((int &)x |= (int)y); } \
+    inline type operator ^(type x, type y) { return (type)((int)x ^ (int)y); } \
+    inline type operator ^=(type &x, type y) { return (type &)((int &)x ^= (int)y); } \
+}
+#else
+# define DEFINE_ENUM_FLAG_OPERATORS(type)
+#endif
+#endif /* DEFINE_ENUM_FLAG_OPERATORS */
+
+#endif  /* _INC_WINDOWS */
+#endif  /* __VKD3D_WINDOWS_H */
diff --git a/dlls/vkd3d/libs/vkd3d-common/debug.c b/dlls/vkd3d/libs/vkd3d-common/debug.c
new file mode 100644
index 00000000000..33deed6592a
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-common/debug.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_debug.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#define VKD3D_DEBUG_BUFFER_COUNT 64
+#define VKD3D_DEBUG_BUFFER_SIZE 512
+
+extern const char *vkd3d_dbg_env_name DECLSPEC_HIDDEN;
+
+static const char *debug_level_names[] =
+{
+    /* VKD3D_DBG_LEVEL_NONE  */ "none",
+    /* VKD3D_DBG_LEVEL_ERR   */ "err",
+    /* VKD3D_DBG_LEVEL_FIXME */ "fixme",
+    /* VKD3D_DBG_LEVEL_WARN  */ "warn",
+    /* VKD3D_DBG_LEVEL_TRACE */ "trace",
+};
+
+enum vkd3d_dbg_level vkd3d_dbg_get_level(void)
+{
+    static unsigned int level = ~0u;
+    const char *vkd3d_debug;
+    unsigned int i;
+
+    if (level != ~0u)
+        return level;
+
+    if (!(vkd3d_debug = getenv(vkd3d_dbg_env_name)))
+        vkd3d_debug = "";
+
+    for (i = 0; i < ARRAY_SIZE(debug_level_names); ++i)
+    {
+        if (!strcmp(debug_level_names[i], vkd3d_debug))
+        {
+            level = i;
+            return level;
+        }
+    }
+
+    /* Default debug level. */
+    level = VKD3D_DBG_LEVEL_FIXME;
+    return level;
+}
+
+void vkd3d_dbg_printf(enum vkd3d_dbg_level level, const char *function, const char *fmt, ...)
+{
+    va_list args;
+
+    if (vkd3d_dbg_get_level() < level)
+        return;
+
+    assert(level < ARRAY_SIZE(debug_level_names));
+
+    fprintf(stderr, "%s:%s: ", debug_level_names[level], function);
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
+
+static char *get_buffer(void)
+{
+    static char buffers[VKD3D_DEBUG_BUFFER_COUNT][VKD3D_DEBUG_BUFFER_SIZE];
+    static LONG buffer_index;
+    LONG current_index;
+
+    current_index = InterlockedIncrement(&buffer_index) % ARRAY_SIZE(buffers);
+    return buffers[current_index];
+}
+
+const char *vkd3d_dbg_vsprintf(const char *fmt, va_list args)
+{
+    char *buffer;
+
+    buffer = get_buffer();
+    vsnprintf(buffer, VKD3D_DEBUG_BUFFER_SIZE, fmt, args);
+    buffer[VKD3D_DEBUG_BUFFER_SIZE - 1] = '\0';
+    return buffer;
+}
+
+const char *vkd3d_dbg_sprintf(const char *fmt, ...)
+{
+    const char *buffer;
+    va_list args;
+
+    va_start(args, fmt);
+    buffer = vkd3d_dbg_vsprintf(fmt, args);
+    va_end(args);
+    return buffer;
+}
+
+const char *debugstr_a(const char *str)
+{
+    char *buffer, *ptr;
+    char c;
+
+    if (!str)
+        return "(null)";
+
+    ptr = buffer = get_buffer();
+
+    *ptr++ = '"';
+    while ((c = *str++) && ptr <= buffer + VKD3D_DEBUG_BUFFER_SIZE - 8)
+    {
+        int escape_char;
+
+        switch (c)
+        {
+            case '"':
+            case '\\':
+            case '\n':
+            case '\r':
+            case '\t':
+                escape_char = c;
+                break;
+            default:
+                escape_char = 0;
+                break;
+        }
+
+        if (escape_char)
+        {
+            *ptr++ = '\\';
+            *ptr++ = escape_char;
+            continue;
+        }
+
+        if (isprint(c))
+        {
+            *ptr++ = c;
+        }
+        else
+        {
+            *ptr++ = '\\';
+            sprintf(ptr, "%02x", c);
+            ptr += 2;
+        }
+    }
+    *ptr++ = '"';
+
+    if (c)
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+    *ptr = '\0';
+
+    return buffer;
+}
+
+static const char *debugstr_w16(const uint16_t *wstr)
+{
+    char *buffer, *ptr;
+    uint16_t c;
+
+    if (!wstr)
+        return "(null)";
+
+    ptr = buffer = get_buffer();
+
+    *ptr++ = '"';
+    while ((c = *wstr++) && ptr <= buffer + VKD3D_DEBUG_BUFFER_SIZE - 10)
+    {
+        int escape_char;
+
+        switch (c)
+        {
+            case '"':
+            case '\\':
+            case '\n':
+            case '\r':
+            case '\t':
+                escape_char = c;
+                break;
+            default:
+                escape_char = 0;
+                break;
+        }
+
+        if (escape_char)
+        {
+            *ptr++ = '\\';
+            *ptr++ = escape_char;
+            continue;
+        }
+
+        if (isprint(c))
+        {
+            *ptr++ = c;
+        }
+        else
+        {
+            *ptr++ = '\\';
+            sprintf(ptr, "%04x", c);
+            ptr += 4;
+        }
+    }
+    *ptr++ = '"';
+
+    if (c)
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+    *ptr = '\0';
+
+    return buffer;
+}
+
+static const char *debugstr_w32(const uint32_t *wstr)
+{
+    char *buffer, *ptr;
+    uint32_t c;
+
+    if (!wstr)
+        return "(null)";
+
+    ptr = buffer = get_buffer();
+
+    *ptr++ = '"';
+    while ((c = *wstr++) && ptr <= buffer + VKD3D_DEBUG_BUFFER_SIZE - 10)
+    {
+        int escape_char;
+
+        switch (c)
+        {
+            case '"':
+            case '\\':
+            case '\n':
+            case '\r':
+            case '\t':
+                escape_char = c;
+                break;
+            default:
+                escape_char = 0;
+                break;
+        }
+
+        if (escape_char)
+        {
+            *ptr++ = '\\';
+            *ptr++ = escape_char;
+            continue;
+        }
+
+        if (isprint(c))
+        {
+            *ptr++ = c;
+        }
+        else
+        {
+            *ptr++ = '\\';
+            sprintf(ptr, "%04x", c);
+            ptr += 4;
+        }
+    }
+    *ptr++ = '"';
+
+    if (c)
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+    *ptr = '\0';
+
+    return buffer;
+}
+
+const char *debugstr_w(const WCHAR *wstr, size_t wchar_size)
+{
+    if (wchar_size == 2)
+        return debugstr_w16((const uint16_t *)wstr);
+    return debugstr_w32((const uint32_t *)wstr);
+}
+
+unsigned int vkd3d_env_var_as_uint(const char *name, unsigned int default_value)
+{
+    const char *value = getenv(name);
+    unsigned long r;
+    char *end_ptr;
+
+    if (value)
+    {
+        errno = 0;
+        r = strtoul(value, &end_ptr, 0);
+        if (!errno && end_ptr != value)
+            return min(r, UINT_MAX);
+    }
+
+    return default_value;
+}
+
+static bool is_option_separator(char c)
+{
+    return c == ',' || c == ';' || c == '\0';
+}
+
+bool vkd3d_debug_list_has_member(const char *string, const char *member)
+{
+    char prev_char, next_char;
+    const char *p;
+
+    p = string;
+    while (p)
+    {
+        if ((p = strstr(p, member)))
+        {
+            prev_char = p > string ? p[-1] : 0;
+            p += strlen(member);
+            next_char = *p;
+
+            if (is_option_separator(prev_char) && is_option_separator(next_char))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+uint64_t vkd3d_parse_debug_options(const char *string,
+        const struct vkd3d_debug_option *options, unsigned int option_count)
+{
+    uint64_t flags = 0;
+    unsigned int i;
+
+    for (i = 0; i < option_count; ++i)
+    {
+        const struct vkd3d_debug_option *opt = &options[i];
+
+        if (vkd3d_debug_list_has_member(string, opt->name))
+            flags |= opt->flag;
+    }
+
+    return flags;
+}
diff --git a/dlls/vkd3d/libs/vkd3d-common/memory.c b/dlls/vkd3d/libs/vkd3d-common/memory.c
new file mode 100644
index 00000000000..2bf8947e090
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-common/memory.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ * Copyright 2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_memory.h"
+
+bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
+{
+    size_t new_capacity, max_capacity;
+    void *new_elements;
+
+    if (element_count <= *capacity)
+        return true;
+
+    max_capacity = ~(size_t)0 / element_size;
+    if (max_capacity < element_count)
+        return false;
+
+    new_capacity = max(*capacity, 4);
+    while (new_capacity < element_count && new_capacity <= max_capacity / 2)
+        new_capacity *= 2;
+
+    if (new_capacity < element_count)
+        new_capacity = element_count;
+
+    if (!(new_elements = vkd3d_realloc(*elements, new_capacity * element_size)))
+        return false;
+
+    *elements = new_elements;
+    *capacity = new_capacity;
+
+    return true;
+}
diff --git a/dlls/vkd3d/libs/vkd3d-common/utf8.c b/dlls/vkd3d/libs/vkd3d-common/utf8.c
new file mode 100644
index 00000000000..8bf4eb05e4f
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-common/utf8.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2000 Alexandre Julliard
+ * Copyright 2019 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_memory.h"
+#include "vkd3d_utf8.h"
+
+#include <inttypes.h>
+
+static size_t vkd3d_utf8_len(uint32_t c)
+{
+    /* 0x00-0x7f: 1 byte */
+    if (c < 0x80)
+        return 1;
+    /* 0x80-0x7ff: 2 bytes */
+    if (c < 0x800)
+        return 2;
+    /* 0x800-0xffff: 3 bytes */
+    if (c < 0x10000)
+        return 3;
+    /* 0x10000-0x10ffff: 4 bytes */
+    return 4;
+}
+
+static void vkd3d_utf8_append(char **dst, uint32_t c)
+{
+    char *d = *dst;
+
+    /* 0x00-0x7f: 1 byte */
+    if (c < 0x80)
+    {
+        d[0] = c;
+        *dst += 1;
+        return;
+    }
+
+    /* 0x80-0x7ff: 2 bytes */
+    if (c < 0x800)
+    {
+        d[1] = 0x80 | (c & 0x3f);
+        c >>= 6;
+        d[0] = 0xc0 | c;
+        *dst += 2;
+        return;
+    }
+
+    /* 0x800-0xffff: 3 bytes */
+    if (c < 0x10000)  /* 0x800-0xffff: 3 bytes */
+    {
+        d[2] = 0x80 | (c & 0x3f);
+        c >>= 6;
+        d[1] = 0x80 | (c & 0x3f);
+        c >>= 6;
+        d[0] = 0xe0 | c;
+        *dst += 3;
+        return;
+    }
+
+    /* 0x10000-0x10ffff: 4 bytes */
+    d[3] = 0x80 | (c & 0x3f);
+    c >>= 6;
+    d[2] = 0x80 | (c & 0x3f);
+    c >>= 6;
+    d[1] = 0x80 | (c & 0x3f);
+    c >>= 6;
+    d[0] = 0xf0 | c;
+    *dst += 4;
+}
+
+static uint32_t vkd3d_utf16_read(const uint16_t **src)
+{
+    const uint16_t *s = *src;
+
+    if (s[0] < 0xd800 || s[0] > 0xdfff) /* Not a surrogate pair. */
+    {
+        *src += 1;
+        return s[0];
+    }
+
+    if (s[0] > 0xdbff /* Invalid high surrogate. */
+            || s[1] < 0xdc00 || s[1] > 0xdfff) /* Invalid low surrogate. */
+    {
+        *src += 1;
+        return 0;
+    }
+
+    *src += 2;
+    return 0x10000 + ((s[0] & 0x3ff) << 10) + (s[1] & 0x3ff);
+}
+
+static char *vkd3d_strdup_w16_utf8(const uint16_t *wstr)
+{
+    const uint16_t *src = wstr;
+    size_t dst_size = 0;
+    char *dst, *utf8;
+    uint32_t c;
+
+    while (*src)
+    {
+        if (!(c = vkd3d_utf16_read(&src)))
+            continue;
+        dst_size += vkd3d_utf8_len(c);
+    }
+    ++dst_size;
+
+    if (!(dst = vkd3d_malloc(dst_size)))
+        return NULL;
+
+    utf8 = dst;
+    src = wstr;
+    while (*src)
+    {
+        if (!(c = vkd3d_utf16_read(&src)))
+            continue;
+        vkd3d_utf8_append(&utf8, c);
+    }
+    *utf8 = 0;
+
+    return dst;
+}
+
+static char *vkd3d_strdup_w32_utf8(const uint32_t *wstr)
+{
+    const uint32_t *src = wstr;
+    size_t dst_size = 0;
+    char *dst, *utf8;
+
+    while (*src)
+        dst_size += vkd3d_utf8_len(*src++);
+    ++dst_size;
+
+    if (!(dst = vkd3d_malloc(dst_size)))
+        return NULL;
+
+    utf8 = dst;
+    src = wstr;
+    while (*src)
+        vkd3d_utf8_append(&utf8, *src++);
+    *utf8 = 0;
+
+    return dst;
+}
+
+char *vkd3d_strdup_w_utf8(const WCHAR *wstr, size_t wchar_size)
+{
+    if (wchar_size == 2)
+        return vkd3d_strdup_w16_utf8((const uint16_t *)wstr);
+    return vkd3d_strdup_w32_utf8((const uint32_t *)wstr);
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/checksum.c b/dlls/vkd3d/libs/vkd3d-shader/checksum.c
new file mode 100644
index 00000000000..b9a7140221e
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/checksum.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * It is based on code in the public domain written by Colin
+ * Plumb in 1993. The algorithm is due to Ron Rivest.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * md5_ctx structure, pass it to md5_init, call md5_update as
+ * needed on buffers full of bytes, and then call md5_final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "vkd3d_shader_private.h"
+
+#define DXBC_CHECKSUM_BLOCK_SIZE 64
+
+STATIC_ASSERT(sizeof(unsigned int) == 4);
+
+struct md5_ctx
+{
+    unsigned int i[2];
+    unsigned int buf[4];
+    unsigned char in[DXBC_CHECKSUM_BLOCK_SIZE];
+    unsigned char digest[16];
+};
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+        (w += f(x, y, z) + data,  w = w << s | w >> (32 - s),  w += x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. md5_update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void md5_transform(unsigned int buf[4], const unsigned int in[16])
+{
+    unsigned int a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byte_reverse(unsigned char *buf, unsigned longs)
+{
+    unsigned int t;
+
+    do
+    {
+        t = ((unsigned)buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned)buf[1] << 8 | buf[0]);
+        *(unsigned int *)buf = t;
+        buf += 4;
+    } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+static void md5_init(struct md5_ctx *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->i[0] = ctx->i[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void md5_update(struct md5_ctx *ctx, const unsigned char *buf, unsigned int len)
+{
+    unsigned int t;
+
+    /* Update bitcount */
+    t = ctx->i[0];
+
+    if ((ctx->i[0] = t + (len << 3)) < t)
+        ctx->i[1]++;        /* Carry from low to high */
+
+    ctx->i[1] += len >> 29;
+    t = (t >> 3) & 0x3f;
+
+    /* Handle any leading odd-sized chunks */
+    if (t)
+    {
+        unsigned char *p = (unsigned char *)ctx->in + t;
+        t = DXBC_CHECKSUM_BLOCK_SIZE - t;
+
+        if (len < t)
+        {
+            memcpy(p, buf, len);
+            return;
+        }
+
+        memcpy(p, buf, t);
+        byte_reverse(ctx->in, 16);
+
+        md5_transform(ctx->buf, (unsigned int *)ctx->in);
+
+        buf += t;
+        len -= t;
+    }
+
+    /* Process data in 64-byte chunks */
+    while (len >= DXBC_CHECKSUM_BLOCK_SIZE)
+    {
+        memcpy(ctx->in, buf, DXBC_CHECKSUM_BLOCK_SIZE);
+        byte_reverse(ctx->in, 16);
+
+        md5_transform(ctx->buf, (unsigned int *)ctx->in);
+
+        buf += DXBC_CHECKSUM_BLOCK_SIZE;
+        len -= DXBC_CHECKSUM_BLOCK_SIZE;
+    }
+
+    /* Handle any remaining bytes of data. */
+    memcpy(ctx->in, buf, len);
+}
+
+static void dxbc_checksum_final(struct md5_ctx *ctx)
+{
+    unsigned int padding;
+    unsigned int length;
+    unsigned int count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->i[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+    ++count;
+
+    /* Bytes of padding needed to make 64 bytes */
+    padding = DXBC_CHECKSUM_BLOCK_SIZE - count;
+
+    /* Pad out to 56 mod 64 */
+    if (padding < 8)
+    {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset(p, 0, padding);
+        byte_reverse(ctx->in, 16);
+        md5_transform(ctx->buf, (unsigned int *)ctx->in);
+
+        /* Now fill the next block */
+        memset(ctx->in, 0, DXBC_CHECKSUM_BLOCK_SIZE);
+    }
+    else
+    {
+        /* Make place for bitcount at the beginning of the block */
+        memmove(&ctx->in[4], ctx->in, count);
+
+        /* Pad block to 60 bytes */
+        memset(p + 4, 0, padding - 4);
+    }
+
+    /* Append length in bits and transform */
+    length = ctx->i[0];
+    memcpy(&ctx->in[0], &length, sizeof(length));
+    byte_reverse(&ctx->in[4], 14);
+    length = ctx->i[0] >> 2 | 0x1;
+    memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length));
+
+    md5_transform(ctx->buf, (unsigned int *)ctx->in);
+    byte_reverse((unsigned char *)ctx->buf, 4);
+    memcpy(ctx->digest, ctx->buf, 16);
+}
+
+#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20
+
+void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4])
+{
+    const uint8_t *ptr = dxbc;
+    struct md5_ctx ctx;
+
+    assert(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT);
+    ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT;
+    size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT;
+
+    md5_init(&ctx);
+    md5_update(&ctx, ptr, size);
+    dxbc_checksum_final(&ctx);
+
+    memcpy(checksum, ctx.digest, sizeof(ctx.digest));
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/dxbc.c b/dlls/vkd3d/libs/vkd3d-shader/dxbc.c
new file mode 100644
index 00000000000..398cd9fbdcf
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/dxbc.c
@@ -0,0 +1,3659 @@
+/*
+ * Copyright 2008-2009 Henri Verbeet for CodeWeavers
+ * Copyright 2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_shader_private.h"
+
+#define VKD3D_SM4_INSTRUCTION_MODIFIER        (0x1u << 31)
+
+#define VKD3D_SM4_MODIFIER_MASK               0x3fu
+
+#define VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT    6
+#define VKD3D_SM5_MODIFIER_DATA_TYPE_MASK     (0xffffu << VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT)
+
+#define VKD3D_SM5_MODIFIER_RESOURCE_TYPE_SHIFT 6
+#define VKD3D_SM5_MODIFIER_RESOURCE_TYPE_MASK (0xfu << VKD3D_SM5_MODIFIER_RESOURCE_TYPE_SHIFT)
+
+#define VKD3D_SM4_AOFFIMMI_U_SHIFT            9
+#define VKD3D_SM4_AOFFIMMI_U_MASK             (0xfu << VKD3D_SM4_AOFFIMMI_U_SHIFT)
+#define VKD3D_SM4_AOFFIMMI_V_SHIFT            13
+#define VKD3D_SM4_AOFFIMMI_V_MASK             (0xfu << VKD3D_SM4_AOFFIMMI_V_SHIFT)
+#define VKD3D_SM4_AOFFIMMI_W_SHIFT            17
+#define VKD3D_SM4_AOFFIMMI_W_MASK             (0xfu << VKD3D_SM4_AOFFIMMI_W_SHIFT)
+
+#define VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT    24
+#define VKD3D_SM4_INSTRUCTION_LENGTH_MASK     (0x1fu << VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT)
+
+#define VKD3D_SM4_INSTRUCTION_FLAGS_SHIFT     11
+#define VKD3D_SM4_INSTRUCTION_FLAGS_MASK      (0x7u << VKD3D_SM4_INSTRUCTION_FLAGS_SHIFT)
+
+#define VKD3D_SM4_RESOURCE_TYPE_SHIFT         11
+#define VKD3D_SM4_RESOURCE_TYPE_MASK          (0xfu << VKD3D_SM4_RESOURCE_TYPE_SHIFT)
+
+#define VKD3D_SM4_PRIMITIVE_TYPE_SHIFT        11
+#define VKD3D_SM4_PRIMITIVE_TYPE_MASK         (0x3fu << VKD3D_SM4_PRIMITIVE_TYPE_SHIFT)
+
+#define VKD3D_SM4_INDEX_TYPE_SHIFT            11
+#define VKD3D_SM4_INDEX_TYPE_MASK             (0x1u << VKD3D_SM4_INDEX_TYPE_SHIFT)
+
+#define VKD3D_SM4_SAMPLER_MODE_SHIFT          11
+#define VKD3D_SM4_SAMPLER_MODE_MASK           (0xfu << VKD3D_SM4_SAMPLER_MODE_SHIFT)
+
+#define VKD3D_SM4_SHADER_DATA_TYPE_SHIFT      11
+#define VKD3D_SM4_SHADER_DATA_TYPE_MASK       (0xfu << VKD3D_SM4_SHADER_DATA_TYPE_SHIFT)
+
+#define VKD3D_SM4_INTERPOLATION_MODE_SHIFT    11
+#define VKD3D_SM4_INTERPOLATION_MODE_MASK     (0xfu << VKD3D_SM4_INTERPOLATION_MODE_SHIFT)
+
+#define VKD3D_SM4_GLOBAL_FLAGS_SHIFT          11
+#define VKD3D_SM4_GLOBAL_FLAGS_MASK           (0xffu << VKD3D_SM4_GLOBAL_FLAGS_SHIFT)
+
+#define VKD3D_SM5_PRECISE_SHIFT               19
+#define VKD3D_SM5_PRECISE_MASK                (0xfu << VKD3D_SM5_PRECISE_SHIFT)
+
+#define VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT   11
+#define VKD3D_SM5_CONTROL_POINT_COUNT_MASK    (0xffu << VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT)
+
+#define VKD3D_SM5_FP_ARRAY_SIZE_SHIFT         16
+#define VKD3D_SM5_FP_TABLE_COUNT_MASK         0xffffu
+
+#define VKD3D_SM5_UAV_FLAGS_SHIFT             15
+#define VKD3D_SM5_UAV_FLAGS_MASK              (0x1ffu << VKD3D_SM5_UAV_FLAGS_SHIFT)
+
+#define VKD3D_SM5_SYNC_FLAGS_SHIFT            11
+#define VKD3D_SM5_SYNC_FLAGS_MASK             (0xffu << VKD3D_SM5_SYNC_FLAGS_SHIFT)
+
+#define VKD3D_SM5_TESSELLATOR_SHIFT           11
+#define VKD3D_SM5_TESSELLATOR_MASK            (0xfu << VKD3D_SM5_TESSELLATOR_SHIFT)
+
+#define VKD3D_SM4_OPCODE_MASK                 0xff
+
+#define VKD3D_SM4_REGISTER_MODIFIER           (0x1u << 31)
+
+#define VKD3D_SM4_ADDRESSING_SHIFT2           28
+#define VKD3D_SM4_ADDRESSING_MASK2            (0x3u << VKD3D_SM4_ADDRESSING_SHIFT2)
+
+#define VKD3D_SM4_ADDRESSING_SHIFT1           25
+#define VKD3D_SM4_ADDRESSING_MASK1            (0x3u << VKD3D_SM4_ADDRESSING_SHIFT1)
+
+#define VKD3D_SM4_ADDRESSING_SHIFT0           22
+#define VKD3D_SM4_ADDRESSING_MASK0            (0x3u << VKD3D_SM4_ADDRESSING_SHIFT0)
+
+#define VKD3D_SM4_REGISTER_ORDER_SHIFT        20
+#define VKD3D_SM4_REGISTER_ORDER_MASK         (0x3u << VKD3D_SM4_REGISTER_ORDER_SHIFT)
+
+#define VKD3D_SM4_REGISTER_TYPE_SHIFT         12
+#define VKD3D_SM4_REGISTER_TYPE_MASK          (0xffu << VKD3D_SM4_REGISTER_TYPE_SHIFT)
+
+#define VKD3D_SM4_SWIZZLE_TYPE_SHIFT          2
+#define VKD3D_SM4_SWIZZLE_TYPE_MASK           (0x3u << VKD3D_SM4_SWIZZLE_TYPE_SHIFT)
+
+#define VKD3D_SM4_DIMENSION_SHIFT             0
+#define VKD3D_SM4_DIMENSION_MASK              (0x3u << VKD3D_SM4_DIMENSION_SHIFT)
+
+#define VKD3D_SM4_WRITEMASK_SHIFT             4
+#define VKD3D_SM4_WRITEMASK_MASK              (0xfu << VKD3D_SM4_WRITEMASK_SHIFT)
+
+#define VKD3D_SM4_SWIZZLE_SHIFT               4
+#define VKD3D_SM4_SWIZZLE_MASK                (0xffu << VKD3D_SM4_SWIZZLE_SHIFT)
+
+#define VKD3D_SM4_VERSION_MAJOR(version)      (((version) >> 4) & 0xf)
+#define VKD3D_SM4_VERSION_MINOR(version)      (((version) >> 0) & 0xf)
+
+#define VKD3D_SM4_ADDRESSING_RELATIVE         0x2
+#define VKD3D_SM4_ADDRESSING_OFFSET           0x1
+
+#define VKD3D_SM4_INSTRUCTION_FLAG_SATURATE   0x4
+
+#define VKD3D_SM4_CONDITIONAL_NZ              (0x1u << 18)
+
+enum vkd3d_sm4_opcode
+{
+    VKD3D_SM4_OP_ADD                              = 0x00,
+    VKD3D_SM4_OP_AND                              = 0x01,
+    VKD3D_SM4_OP_BREAK                            = 0x02,
+    VKD3D_SM4_OP_BREAKC                           = 0x03,
+    VKD3D_SM4_OP_CASE                             = 0x06,
+    VKD3D_SM4_OP_CONTINUE                         = 0x07,
+    VKD3D_SM4_OP_CONTINUEC                        = 0x08,
+    VKD3D_SM4_OP_CUT                              = 0x09,
+    VKD3D_SM4_OP_DEFAULT                          = 0x0a,
+    VKD3D_SM4_OP_DERIV_RTX                        = 0x0b,
+    VKD3D_SM4_OP_DERIV_RTY                        = 0x0c,
+    VKD3D_SM4_OP_DISCARD                          = 0x0d,
+    VKD3D_SM4_OP_DIV                              = 0x0e,
+    VKD3D_SM4_OP_DP2                              = 0x0f,
+    VKD3D_SM4_OP_DP3                              = 0x10,
+    VKD3D_SM4_OP_DP4                              = 0x11,
+    VKD3D_SM4_OP_ELSE                             = 0x12,
+    VKD3D_SM4_OP_EMIT                             = 0x13,
+    VKD3D_SM4_OP_ENDIF                            = 0x15,
+    VKD3D_SM4_OP_ENDLOOP                          = 0x16,
+    VKD3D_SM4_OP_ENDSWITCH                        = 0x17,
+    VKD3D_SM4_OP_EQ                               = 0x18,
+    VKD3D_SM4_OP_EXP                              = 0x19,
+    VKD3D_SM4_OP_FRC                              = 0x1a,
+    VKD3D_SM4_OP_FTOI                             = 0x1b,
+    VKD3D_SM4_OP_FTOU                             = 0x1c,
+    VKD3D_SM4_OP_GE                               = 0x1d,
+    VKD3D_SM4_OP_IADD                             = 0x1e,
+    VKD3D_SM4_OP_IF                               = 0x1f,
+    VKD3D_SM4_OP_IEQ                              = 0x20,
+    VKD3D_SM4_OP_IGE                              = 0x21,
+    VKD3D_SM4_OP_ILT                              = 0x22,
+    VKD3D_SM4_OP_IMAD                             = 0x23,
+    VKD3D_SM4_OP_IMAX                             = 0x24,
+    VKD3D_SM4_OP_IMIN                             = 0x25,
+    VKD3D_SM4_OP_IMUL                             = 0x26,
+    VKD3D_SM4_OP_INE                              = 0x27,
+    VKD3D_SM4_OP_INEG                             = 0x28,
+    VKD3D_SM4_OP_ISHL                             = 0x29,
+    VKD3D_SM4_OP_ISHR                             = 0x2a,
+    VKD3D_SM4_OP_ITOF                             = 0x2b,
+    VKD3D_SM4_OP_LABEL                            = 0x2c,
+    VKD3D_SM4_OP_LD                               = 0x2d,
+    VKD3D_SM4_OP_LD2DMS                           = 0x2e,
+    VKD3D_SM4_OP_LOG                              = 0x2f,
+    VKD3D_SM4_OP_LOOP                             = 0x30,
+    VKD3D_SM4_OP_LT                               = 0x31,
+    VKD3D_SM4_OP_MAD                              = 0x32,
+    VKD3D_SM4_OP_MIN                              = 0x33,
+    VKD3D_SM4_OP_MAX                              = 0x34,
+    VKD3D_SM4_OP_SHADER_DATA                      = 0x35,
+    VKD3D_SM4_OP_MOV                              = 0x36,
+    VKD3D_SM4_OP_MOVC                             = 0x37,
+    VKD3D_SM4_OP_MUL                              = 0x38,
+    VKD3D_SM4_OP_NE                               = 0x39,
+    VKD3D_SM4_OP_NOP                              = 0x3a,
+    VKD3D_SM4_OP_NOT                              = 0x3b,
+    VKD3D_SM4_OP_OR                               = 0x3c,
+    VKD3D_SM4_OP_RESINFO                          = 0x3d,
+    VKD3D_SM4_OP_RET                              = 0x3e,
+    VKD3D_SM4_OP_RETC                             = 0x3f,
+    VKD3D_SM4_OP_ROUND_NE                         = 0x40,
+    VKD3D_SM4_OP_ROUND_NI                         = 0x41,
+    VKD3D_SM4_OP_ROUND_PI                         = 0x42,
+    VKD3D_SM4_OP_ROUND_Z                          = 0x43,
+    VKD3D_SM4_OP_RSQ                              = 0x44,
+    VKD3D_SM4_OP_SAMPLE                           = 0x45,
+    VKD3D_SM4_OP_SAMPLE_C                         = 0x46,
+    VKD3D_SM4_OP_SAMPLE_C_LZ                      = 0x47,
+    VKD3D_SM4_OP_SAMPLE_LOD                       = 0x48,
+    VKD3D_SM4_OP_SAMPLE_GRAD                      = 0x49,
+    VKD3D_SM4_OP_SAMPLE_B                         = 0x4a,
+    VKD3D_SM4_OP_SQRT                             = 0x4b,
+    VKD3D_SM4_OP_SWITCH                           = 0x4c,
+    VKD3D_SM4_OP_SINCOS                           = 0x4d,
+    VKD3D_SM4_OP_UDIV                             = 0x4e,
+    VKD3D_SM4_OP_ULT                              = 0x4f,
+    VKD3D_SM4_OP_UGE                              = 0x50,
+    VKD3D_SM4_OP_UMUL                             = 0x51,
+    VKD3D_SM4_OP_UMAX                             = 0x53,
+    VKD3D_SM4_OP_UMIN                             = 0x54,
+    VKD3D_SM4_OP_USHR                             = 0x55,
+    VKD3D_SM4_OP_UTOF                             = 0x56,
+    VKD3D_SM4_OP_XOR                              = 0x57,
+    VKD3D_SM4_OP_DCL_RESOURCE                     = 0x58,
+    VKD3D_SM4_OP_DCL_CONSTANT_BUFFER              = 0x59,
+    VKD3D_SM4_OP_DCL_SAMPLER                      = 0x5a,
+    VKD3D_SM4_OP_DCL_INDEX_RANGE                  = 0x5b,
+    VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY              = 0x5c,
+    VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE              = 0x5d,
+    VKD3D_SM4_OP_DCL_VERTICES_OUT                 = 0x5e,
+    VKD3D_SM4_OP_DCL_INPUT                        = 0x5f,
+    VKD3D_SM4_OP_DCL_INPUT_SGV                    = 0x60,
+    VKD3D_SM4_OP_DCL_INPUT_SIV                    = 0x61,
+    VKD3D_SM4_OP_DCL_INPUT_PS                     = 0x62,
+    VKD3D_SM4_OP_DCL_INPUT_PS_SGV                 = 0x63,
+    VKD3D_SM4_OP_DCL_INPUT_PS_SIV                 = 0x64,
+    VKD3D_SM4_OP_DCL_OUTPUT                       = 0x65,
+    VKD3D_SM4_OP_DCL_OUTPUT_SIV                   = 0x67,
+    VKD3D_SM4_OP_DCL_TEMPS                        = 0x68,
+    VKD3D_SM4_OP_DCL_INDEXABLE_TEMP               = 0x69,
+    VKD3D_SM4_OP_DCL_GLOBAL_FLAGS                 = 0x6a,
+    VKD3D_SM4_OP_LOD                              = 0x6c,
+    VKD3D_SM4_OP_GATHER4                          = 0x6d,
+    VKD3D_SM4_OP_SAMPLE_POS                       = 0x6e,
+    VKD3D_SM4_OP_SAMPLE_INFO                      = 0x6f,
+    VKD3D_SM5_OP_HS_DECLS                         = 0x71,
+    VKD3D_SM5_OP_HS_CONTROL_POINT_PHASE           = 0x72,
+    VKD3D_SM5_OP_HS_FORK_PHASE                    = 0x73,
+    VKD3D_SM5_OP_HS_JOIN_PHASE                    = 0x74,
+    VKD3D_SM5_OP_EMIT_STREAM                      = 0x75,
+    VKD3D_SM5_OP_CUT_STREAM                       = 0x76,
+    VKD3D_SM5_OP_FCALL                            = 0x78,
+    VKD3D_SM5_OP_BUFINFO                          = 0x79,
+    VKD3D_SM5_OP_DERIV_RTX_COARSE                 = 0x7a,
+    VKD3D_SM5_OP_DERIV_RTX_FINE                   = 0x7b,
+    VKD3D_SM5_OP_DERIV_RTY_COARSE                 = 0x7c,
+    VKD3D_SM5_OP_DERIV_RTY_FINE                   = 0x7d,
+    VKD3D_SM5_OP_GATHER4_C                        = 0x7e,
+    VKD3D_SM5_OP_GATHER4_PO                       = 0x7f,
+    VKD3D_SM5_OP_GATHER4_PO_C                     = 0x80,
+    VKD3D_SM5_OP_RCP                              = 0x81,
+    VKD3D_SM5_OP_F32TOF16                         = 0x82,
+    VKD3D_SM5_OP_F16TOF32                         = 0x83,
+    VKD3D_SM5_OP_COUNTBITS                        = 0x86,
+    VKD3D_SM5_OP_FIRSTBIT_HI                      = 0x87,
+    VKD3D_SM5_OP_FIRSTBIT_LO                      = 0x88,
+    VKD3D_SM5_OP_FIRSTBIT_SHI                     = 0x89,
+    VKD3D_SM5_OP_UBFE                             = 0x8a,
+    VKD3D_SM5_OP_IBFE                             = 0x8b,
+    VKD3D_SM5_OP_BFI                              = 0x8c,
+    VKD3D_SM5_OP_BFREV                            = 0x8d,
+    VKD3D_SM5_OP_SWAPC                            = 0x8e,
+    VKD3D_SM5_OP_DCL_STREAM                       = 0x8f,
+    VKD3D_SM5_OP_DCL_FUNCTION_BODY                = 0x90,
+    VKD3D_SM5_OP_DCL_FUNCTION_TABLE               = 0x91,
+    VKD3D_SM5_OP_DCL_INTERFACE                    = 0x92,
+    VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT    = 0x93,
+    VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT   = 0x94,
+    VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN           = 0x95,
+    VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING     = 0x96,
+    VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE = 0x97,
+    VKD3D_SM5_OP_DCL_HS_MAX_TESSFACTOR            = 0x98,
+    VKD3D_SM5_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT = 0x99,
+    VKD3D_SM5_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT = 0x9a,
+    VKD3D_SM5_OP_DCL_THREAD_GROUP                 = 0x9b,
+    VKD3D_SM5_OP_DCL_UAV_TYPED                    = 0x9c,
+    VKD3D_SM5_OP_DCL_UAV_RAW                      = 0x9d,
+    VKD3D_SM5_OP_DCL_UAV_STRUCTURED               = 0x9e,
+    VKD3D_SM5_OP_DCL_TGSM_RAW                     = 0x9f,
+    VKD3D_SM5_OP_DCL_TGSM_STRUCTURED              = 0xa0,
+    VKD3D_SM5_OP_DCL_RESOURCE_RAW                 = 0xa1,
+    VKD3D_SM5_OP_DCL_RESOURCE_STRUCTURED          = 0xa2,
+    VKD3D_SM5_OP_LD_UAV_TYPED                     = 0xa3,
+    VKD3D_SM5_OP_STORE_UAV_TYPED                  = 0xa4,
+    VKD3D_SM5_OP_LD_RAW                           = 0xa5,
+    VKD3D_SM5_OP_STORE_RAW                        = 0xa6,
+    VKD3D_SM5_OP_LD_STRUCTURED                    = 0xa7,
+    VKD3D_SM5_OP_STORE_STRUCTURED                 = 0xa8,
+    VKD3D_SM5_OP_ATOMIC_AND                       = 0xa9,
+    VKD3D_SM5_OP_ATOMIC_OR                        = 0xaa,
+    VKD3D_SM5_OP_ATOMIC_XOR                       = 0xab,
+    VKD3D_SM5_OP_ATOMIC_CMP_STORE                 = 0xac,
+    VKD3D_SM5_OP_ATOMIC_IADD                      = 0xad,
+    VKD3D_SM5_OP_ATOMIC_IMAX                      = 0xae,
+    VKD3D_SM5_OP_ATOMIC_IMIN                      = 0xaf,
+    VKD3D_SM5_OP_ATOMIC_UMAX                      = 0xb0,
+    VKD3D_SM5_OP_ATOMIC_UMIN                      = 0xb1,
+    VKD3D_SM5_OP_IMM_ATOMIC_ALLOC                 = 0xb2,
+    VKD3D_SM5_OP_IMM_ATOMIC_CONSUME               = 0xb3,
+    VKD3D_SM5_OP_IMM_ATOMIC_IADD                  = 0xb4,
+    VKD3D_SM5_OP_IMM_ATOMIC_AND                   = 0xb5,
+    VKD3D_SM5_OP_IMM_ATOMIC_OR                    = 0xb6,
+    VKD3D_SM5_OP_IMM_ATOMIC_XOR                   = 0xb7,
+    VKD3D_SM5_OP_IMM_ATOMIC_EXCH                  = 0xb8,
+    VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH              = 0xb9,
+    VKD3D_SM5_OP_IMM_ATOMIC_IMAX                  = 0xba,
+    VKD3D_SM5_OP_IMM_ATOMIC_IMIN                  = 0xbb,
+    VKD3D_SM5_OP_IMM_ATOMIC_UMAX                  = 0xbc,
+    VKD3D_SM5_OP_IMM_ATOMIC_UMIN                  = 0xbd,
+    VKD3D_SM5_OP_SYNC                             = 0xbe,
+    VKD3D_SM5_OP_EVAL_SAMPLE_INDEX                = 0xcc,
+    VKD3D_SM5_OP_EVAL_CENTROID                    = 0xcd,
+    VKD3D_SM5_OP_DCL_GS_INSTANCES                 = 0xce,
+};
+
+enum vkd3d_sm4_instruction_modifier
+{
+    VKD3D_SM4_MODIFIER_AOFFIMMI         = 0x1,
+    VKD3D_SM5_MODIFIER_RESOURCE_TYPE    = 0x2,
+    VKD3D_SM5_MODIFIER_DATA_TYPE        = 0x3,
+};
+
+enum vkd3d_sm4_register_type
+{
+    VKD3D_SM4_RT_TEMP                    = 0x00,
+    VKD3D_SM4_RT_INPUT                   = 0x01,
+    VKD3D_SM4_RT_OUTPUT                  = 0x02,
+    VKD3D_SM4_RT_INDEXABLE_TEMP          = 0x03,
+    VKD3D_SM4_RT_IMMCONST                = 0x04,
+    VKD3D_SM4_RT_SAMPLER                 = 0x06,
+    VKD3D_SM4_RT_RESOURCE                = 0x07,
+    VKD3D_SM4_RT_CONSTBUFFER             = 0x08,
+    VKD3D_SM4_RT_IMMCONSTBUFFER          = 0x09,
+    VKD3D_SM4_RT_PRIMID                  = 0x0b,
+    VKD3D_SM4_RT_DEPTHOUT                = 0x0c,
+    VKD3D_SM4_RT_NULL                    = 0x0d,
+    VKD3D_SM4_RT_RASTERIZER              = 0x0e,
+    VKD3D_SM4_RT_OMASK                   = 0x0f,
+    VKD3D_SM5_RT_STREAM                  = 0x10,
+    VKD3D_SM5_RT_FUNCTION_BODY           = 0x11,
+    VKD3D_SM5_RT_FUNCTION_POINTER        = 0x13,
+    VKD3D_SM5_RT_OUTPUT_CONTROL_POINT_ID = 0x16,
+    VKD3D_SM5_RT_FORK_INSTANCE_ID        = 0x17,
+    VKD3D_SM5_RT_JOIN_INSTANCE_ID        = 0x18,
+    VKD3D_SM5_RT_INPUT_CONTROL_POINT     = 0x19,
+    VKD3D_SM5_RT_OUTPUT_CONTROL_POINT    = 0x1a,
+    VKD3D_SM5_RT_PATCH_CONSTANT_DATA     = 0x1b,
+    VKD3D_SM5_RT_DOMAIN_LOCATION         = 0x1c,
+    VKD3D_SM5_RT_UAV                     = 0x1e,
+    VKD3D_SM5_RT_SHARED_MEMORY           = 0x1f,
+    VKD3D_SM5_RT_THREAD_ID               = 0x20,
+    VKD3D_SM5_RT_THREAD_GROUP_ID         = 0x21,
+    VKD3D_SM5_RT_LOCAL_THREAD_ID         = 0x22,
+    VKD3D_SM5_RT_COVERAGE                = 0x23,
+    VKD3D_SM5_RT_LOCAL_THREAD_INDEX      = 0x24,
+    VKD3D_SM5_RT_GS_INSTANCE_ID          = 0x25,
+    VKD3D_SM5_RT_DEPTHOUT_GREATER_EQUAL  = 0x26,
+    VKD3D_SM5_RT_DEPTHOUT_LESS_EQUAL     = 0x27,
+};
+
+enum vkd3d_sm4_output_primitive_type
+{
+    VKD3D_SM4_OUTPUT_PT_POINTLIST     = 0x1,
+    VKD3D_SM4_OUTPUT_PT_LINESTRIP     = 0x3,
+    VKD3D_SM4_OUTPUT_PT_TRIANGLESTRIP = 0x5,
+};
+
+enum vkd3d_sm4_input_primitive_type
+{
+    VKD3D_SM4_INPUT_PT_POINT          = 0x01,
+    VKD3D_SM4_INPUT_PT_LINE           = 0x02,
+    VKD3D_SM4_INPUT_PT_TRIANGLE       = 0x03,
+    VKD3D_SM4_INPUT_PT_LINEADJ        = 0x06,
+    VKD3D_SM4_INPUT_PT_TRIANGLEADJ    = 0x07,
+    VKD3D_SM5_INPUT_PT_PATCH1         = 0x08,
+    VKD3D_SM5_INPUT_PT_PATCH2         = 0x09,
+    VKD3D_SM5_INPUT_PT_PATCH3         = 0x0a,
+    VKD3D_SM5_INPUT_PT_PATCH4         = 0x0b,
+    VKD3D_SM5_INPUT_PT_PATCH5         = 0x0c,
+    VKD3D_SM5_INPUT_PT_PATCH6         = 0x0d,
+    VKD3D_SM5_INPUT_PT_PATCH7         = 0x0e,
+    VKD3D_SM5_INPUT_PT_PATCH8         = 0x0f,
+    VKD3D_SM5_INPUT_PT_PATCH9         = 0x10,
+    VKD3D_SM5_INPUT_PT_PATCH10        = 0x11,
+    VKD3D_SM5_INPUT_PT_PATCH11        = 0x12,
+    VKD3D_SM5_INPUT_PT_PATCH12        = 0x13,
+    VKD3D_SM5_INPUT_PT_PATCH13        = 0x14,
+    VKD3D_SM5_INPUT_PT_PATCH14        = 0x15,
+    VKD3D_SM5_INPUT_PT_PATCH15        = 0x16,
+    VKD3D_SM5_INPUT_PT_PATCH16        = 0x17,
+    VKD3D_SM5_INPUT_PT_PATCH17        = 0x18,
+    VKD3D_SM5_INPUT_PT_PATCH18        = 0x19,
+    VKD3D_SM5_INPUT_PT_PATCH19        = 0x1a,
+    VKD3D_SM5_INPUT_PT_PATCH20        = 0x1b,
+    VKD3D_SM5_INPUT_PT_PATCH21        = 0x1c,
+    VKD3D_SM5_INPUT_PT_PATCH22        = 0x1d,
+    VKD3D_SM5_INPUT_PT_PATCH23        = 0x1e,
+    VKD3D_SM5_INPUT_PT_PATCH24        = 0x1f,
+    VKD3D_SM5_INPUT_PT_PATCH25        = 0x20,
+    VKD3D_SM5_INPUT_PT_PATCH26        = 0x21,
+    VKD3D_SM5_INPUT_PT_PATCH27        = 0x22,
+    VKD3D_SM5_INPUT_PT_PATCH28        = 0x23,
+    VKD3D_SM5_INPUT_PT_PATCH29        = 0x24,
+    VKD3D_SM5_INPUT_PT_PATCH30        = 0x25,
+    VKD3D_SM5_INPUT_PT_PATCH31        = 0x26,
+    VKD3D_SM5_INPUT_PT_PATCH32        = 0x27,
+};
+
+enum vkd3d_sm4_swizzle_type
+{
+    VKD3D_SM4_SWIZZLE_NONE            = 0x0,
+    VKD3D_SM4_SWIZZLE_VEC4            = 0x1,
+    VKD3D_SM4_SWIZZLE_SCALAR          = 0x2,
+};
+
+enum vkd3d_sm4_dimension
+{
+    VKD3D_SM4_DIMENSION_NONE    = 0x0,
+    VKD3D_SM4_DIMENSION_SCALAR  = 0x1,
+    VKD3D_SM4_DIMENSION_VEC4    = 0x2,
+};
+
+enum vkd3d_sm4_resource_type
+{
+    VKD3D_SM4_RESOURCE_BUFFER             = 0x1,
+    VKD3D_SM4_RESOURCE_TEXTURE_1D         = 0x2,
+    VKD3D_SM4_RESOURCE_TEXTURE_2D         = 0x3,
+    VKD3D_SM4_RESOURCE_TEXTURE_2DMS       = 0x4,
+    VKD3D_SM4_RESOURCE_TEXTURE_3D         = 0x5,
+    VKD3D_SM4_RESOURCE_TEXTURE_CUBE       = 0x6,
+    VKD3D_SM4_RESOURCE_TEXTURE_1DARRAY    = 0x7,
+    VKD3D_SM4_RESOURCE_TEXTURE_2DARRAY    = 0x8,
+    VKD3D_SM4_RESOURCE_TEXTURE_2DMSARRAY  = 0x9,
+    VKD3D_SM4_RESOURCE_TEXTURE_CUBEARRAY  = 0xa,
+};
+
+enum vkd3d_sm4_data_type
+{
+    VKD3D_SM4_DATA_UNORM  = 0x1,
+    VKD3D_SM4_DATA_SNORM  = 0x2,
+    VKD3D_SM4_DATA_INT    = 0x3,
+    VKD3D_SM4_DATA_UINT   = 0x4,
+    VKD3D_SM4_DATA_FLOAT  = 0x5,
+};
+
+enum vkd3d_sm4_sampler_mode
+{
+    VKD3D_SM4_SAMPLER_DEFAULT    = 0x0,
+    VKD3D_SM4_SAMPLER_COMPARISON = 0x1,
+};
+
+enum vkd3d_sm4_shader_data_type
+{
+    VKD3D_SM4_SHADER_DATA_IMMEDIATE_CONSTANT_BUFFER = 0x3,
+    VKD3D_SM4_SHADER_DATA_MESSAGE                   = 0x4,
+};
+
+struct vkd3d_shader_src_param_entry
+{
+    struct list entry;
+    struct vkd3d_shader_src_param param;
+};
+
+struct vkd3d_sm4_data
+{
+    struct vkd3d_shader_version shader_version;
+    const DWORD *start, *end;
+
+    unsigned int output_map[MAX_REG_OUTPUT];
+
+    struct vkd3d_shader_src_param src_param[5];
+    struct vkd3d_shader_dst_param dst_param[2];
+    struct list src_free;
+    struct list src;
+    struct vkd3d_shader_immediate_constant_buffer icb;
+};
+
+struct vkd3d_sm4_opcode_info
+{
+    enum vkd3d_sm4_opcode opcode;
+    enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+    const char *dst_info;
+    const char *src_info;
+    void (*read_opcode_func)(struct vkd3d_shader_instruction *ins,
+            DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+            struct vkd3d_sm4_data *priv);
+};
+
+static const enum vkd3d_primitive_type output_primitive_type_table[] =
+{
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* VKD3D_SM4_OUTPUT_PT_POINTLIST */       VKD3D_PT_POINTLIST,
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* VKD3D_SM4_OUTPUT_PT_LINESTRIP */       VKD3D_PT_LINESTRIP,
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* VKD3D_SM4_OUTPUT_PT_TRIANGLESTRIP */   VKD3D_PT_TRIANGLESTRIP,
+};
+
+static const enum vkd3d_primitive_type input_primitive_type_table[] =
+{
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* VKD3D_SM4_INPUT_PT_POINT */            VKD3D_PT_POINTLIST,
+    /* VKD3D_SM4_INPUT_PT_LINE */             VKD3D_PT_LINELIST,
+    /* VKD3D_SM4_INPUT_PT_TRIANGLE */         VKD3D_PT_TRIANGLELIST,
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* UNKNOWN */                             VKD3D_PT_UNDEFINED,
+    /* VKD3D_SM4_INPUT_PT_LINEADJ */          VKD3D_PT_LINELIST_ADJ,
+    /* VKD3D_SM4_INPUT_PT_TRIANGLEADJ */      VKD3D_PT_TRIANGLELIST_ADJ,
+};
+
+static const enum vkd3d_shader_resource_type resource_type_table[] =
+{
+    /* 0 */                                       VKD3D_SHADER_RESOURCE_NONE,
+    /* VKD3D_SM4_RESOURCE_BUFFER */               VKD3D_SHADER_RESOURCE_BUFFER,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_1D */           VKD3D_SHADER_RESOURCE_TEXTURE_1D,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_2D */           VKD3D_SHADER_RESOURCE_TEXTURE_2D,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_2DMS */         VKD3D_SHADER_RESOURCE_TEXTURE_2DMS,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_3D */           VKD3D_SHADER_RESOURCE_TEXTURE_3D,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_CUBE */         VKD3D_SHADER_RESOURCE_TEXTURE_CUBE,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_1DARRAY */      VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_2DARRAY */      VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_2DMSARRAY */    VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY,
+    /* VKD3D_SM4_RESOURCE_TEXTURE_CUBEARRAY */    VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY,
+};
+
+static const enum vkd3d_data_type data_type_table[] =
+{
+    /* 0 */                       VKD3D_DATA_FLOAT,
+    /* VKD3D_SM4_DATA_UNORM */    VKD3D_DATA_UNORM,
+    /* VKD3D_SM4_DATA_SNORM */    VKD3D_DATA_SNORM,
+    /* VKD3D_SM4_DATA_INT */      VKD3D_DATA_INT,
+    /* VKD3D_SM4_DATA_UINT */     VKD3D_DATA_UINT,
+    /* VKD3D_SM4_DATA_FLOAT */    VKD3D_DATA_FLOAT,
+};
+
+static bool shader_is_sm_5_1(const struct vkd3d_sm4_data *priv)
+{
+    const struct vkd3d_shader_version *version = &priv->shader_version;
+    return version->major >= 5 && version->minor >= 1;
+}
+
+static bool shader_sm4_read_src_param(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        enum vkd3d_data_type data_type, struct vkd3d_shader_src_param *src_param);
+static bool shader_sm4_read_dst_param(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        enum vkd3d_data_type data_type, struct vkd3d_shader_dst_param *dst_param);
+
+static bool shader_sm4_read_register_space(struct vkd3d_sm4_data *priv,
+        const DWORD **ptr, const DWORD *end, unsigned int *register_space)
+{
+    *register_space = 0;
+
+    if (!shader_is_sm_5_1(priv))
+        return true;
+
+    if (*ptr >= end)
+    {
+        WARN("Invalid ptr %p >= end %p.\n", *ptr, end);
+        return false;
+    }
+
+    *register_space = *(*ptr)++;
+    return true;
+}
+
+static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT, &priv->src_param[0]);
+    ins->flags = (opcode_token & VKD3D_SM4_CONDITIONAL_NZ) ?
+            VKD3D_SHADER_CONDITIONAL_OP_NZ : VKD3D_SHADER_CONDITIONAL_OP_Z;
+}
+
+static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    enum vkd3d_sm4_shader_data_type type;
+    unsigned int icb_size;
+
+    type = (opcode_token & VKD3D_SM4_SHADER_DATA_TYPE_MASK) >> VKD3D_SM4_SHADER_DATA_TYPE_SHIFT;
+    if (type != VKD3D_SM4_SHADER_DATA_IMMEDIATE_CONSTANT_BUFFER)
+    {
+        FIXME("Ignoring shader data type %#x.\n", type);
+        ins->handler_idx = VKD3DSIH_NOP;
+        return;
+    }
+
+    ++tokens;
+    icb_size = token_count - 1;
+    if (icb_size % 4 || icb_size > MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE)
+    {
+        FIXME("Unexpected immediate constant buffer size %u.\n", icb_size);
+        ins->handler_idx = VKD3DSIH_INVALID;
+        return;
+    }
+
+    priv->icb.vec4_count = icb_size / 4;
+    memcpy(priv->icb.data, tokens, sizeof(*tokens) * icb_size);
+    ins->declaration.icb = &priv->icb;
+}
+
+static unsigned int shader_sm4_map_resource_idx(struct vkd3d_shader_register *reg, const struct vkd3d_sm4_data *priv)
+{
+    if (shader_is_sm_5_1(priv))
+        return reg->idx[1].offset;
+    else
+        return reg->idx[0].offset;
+}
+
+static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_semantic *semantic = &ins->declaration.semantic;
+    enum vkd3d_sm4_resource_type resource_type;
+    const DWORD *end = &tokens[token_count];
+    enum vkd3d_sm4_data_type data_type;
+    enum vkd3d_data_type reg_data_type;
+    DWORD components;
+
+    resource_type = (opcode_token & VKD3D_SM4_RESOURCE_TYPE_MASK) >> VKD3D_SM4_RESOURCE_TYPE_SHIFT;
+    if (!resource_type || (resource_type >= ARRAY_SIZE(resource_type_table)))
+    {
+        FIXME("Unhandled resource type %#x.\n", resource_type);
+        semantic->resource_type = VKD3D_SHADER_RESOURCE_NONE;
+    }
+    else
+    {
+        semantic->resource_type = resource_type_table[resource_type];
+    }
+    reg_data_type = opcode == VKD3D_SM4_OP_DCL_RESOURCE ? VKD3D_DATA_RESOURCE : VKD3D_DATA_UAV;
+    shader_sm4_read_dst_param(priv, &tokens, end, reg_data_type, &semantic->resource.reg);
+    semantic->resource.register_index = shader_sm4_map_resource_idx(&semantic->resource.reg.reg, priv);
+
+    components = *tokens++;
+    if ((components & 0xfff0) != (components & 0xf) * 0x1110)
+        FIXME("Components (%#x) have different data types.\n", components);
+    data_type = components & 0xf;
+
+    if (!data_type || (data_type >= ARRAY_SIZE(data_type_table)))
+    {
+        FIXME("Unhandled data type %#x.\n", data_type);
+        semantic->resource_data_type = VKD3D_DATA_FLOAT;
+    }
+    else
+    {
+        semantic->resource_data_type = data_type_table[data_type];
+    }
+
+    if (reg_data_type == VKD3D_DATA_UAV)
+        ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT;
+
+    shader_sm4_read_register_space(priv, &tokens, end, &semantic->resource.register_space);
+}
+
+static void shader_sm4_read_dcl_constant_buffer(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    const DWORD *end = &tokens[token_count];
+
+    shader_sm4_read_src_param(priv, &tokens, end, VKD3D_DATA_FLOAT, &ins->declaration.cb.src);
+    ins->declaration.cb.register_index = shader_sm4_map_resource_idx(&ins->declaration.cb.src.reg, priv);
+    if (opcode_token & VKD3D_SM4_INDEX_TYPE_MASK)
+        ins->flags |= VKD3DSI_INDEXED_DYNAMIC;
+
+    ins->declaration.cb.size = ins->declaration.cb.src.reg.idx[2].offset;
+    ins->declaration.cb.register_space = 0;
+
+    if (shader_is_sm_5_1(priv))
+    {
+        if (tokens >= end)
+        {
+            FIXME("Invalid ptr %p >= end %p.\n", tokens, end);
+            return;
+        }
+
+        ins->declaration.cb.size = *tokens++;
+        shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.cb.register_space);
+    }
+}
+
+static void shader_sm4_read_dcl_sampler(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    const DWORD *end = &tokens[token_count];
+
+    ins->flags = (opcode_token & VKD3D_SM4_SAMPLER_MODE_MASK) >> VKD3D_SM4_SAMPLER_MODE_SHIFT;
+    if (ins->flags & ~VKD3D_SM4_SAMPLER_COMPARISON)
+        FIXME("Unhandled sampler mode %#x.\n", ins->flags);
+    shader_sm4_read_src_param(priv, &tokens, end, VKD3D_DATA_SAMPLER, &ins->declaration.sampler.src);
+    ins->declaration.sampler.register_index = shader_sm4_map_resource_idx(&ins->declaration.sampler.src.reg, priv);
+    shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.sampler.register_space);
+}
+
+static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE,
+            &ins->declaration.index_range.dst);
+    ins->declaration.index_range.register_count = *tokens;
+}
+
+static void shader_sm4_read_dcl_output_topology(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    enum vkd3d_sm4_output_primitive_type primitive_type;
+
+    primitive_type = (opcode_token & VKD3D_SM4_PRIMITIVE_TYPE_MASK) >> VKD3D_SM4_PRIMITIVE_TYPE_SHIFT;
+    if (primitive_type >= ARRAY_SIZE(output_primitive_type_table))
+        ins->declaration.primitive_type.type = VKD3D_PT_UNDEFINED;
+    else
+        ins->declaration.primitive_type.type = output_primitive_type_table[primitive_type];
+
+    if (ins->declaration.primitive_type.type == VKD3D_PT_UNDEFINED)
+        FIXME("Unhandled output primitive type %#x.\n", primitive_type);
+}
+
+static void shader_sm4_read_dcl_input_primitive(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    enum vkd3d_sm4_input_primitive_type primitive_type;
+
+    primitive_type = (opcode_token & VKD3D_SM4_PRIMITIVE_TYPE_MASK) >> VKD3D_SM4_PRIMITIVE_TYPE_SHIFT;
+    if (VKD3D_SM5_INPUT_PT_PATCH1 <= primitive_type && primitive_type <= VKD3D_SM5_INPUT_PT_PATCH32)
+    {
+        ins->declaration.primitive_type.type = VKD3D_PT_PATCH;
+        ins->declaration.primitive_type.patch_vertex_count = primitive_type - VKD3D_SM5_INPUT_PT_PATCH1 + 1;
+    }
+    else if (primitive_type >= ARRAY_SIZE(input_primitive_type_table))
+    {
+        ins->declaration.primitive_type.type = VKD3D_PT_UNDEFINED;
+    }
+    else
+    {
+        ins->declaration.primitive_type.type = input_primitive_type_table[primitive_type];
+    }
+
+    if (ins->declaration.primitive_type.type == VKD3D_PT_UNDEFINED)
+        FIXME("Unhandled input primitive type %#x.\n", primitive_type);
+}
+
+static void shader_sm4_read_declaration_count(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.count = *tokens;
+}
+
+static void shader_sm4_read_declaration_dst(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, &ins->declaration.dst);
+}
+
+static void shader_sm4_read_declaration_register_semantic(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT,
+            &ins->declaration.register_semantic.reg);
+    ins->declaration.register_semantic.sysval_semantic = *tokens;
+}
+
+static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT;
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, &ins->declaration.dst);
+}
+
+static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT;
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT,
+            &ins->declaration.register_semantic.reg);
+    ins->declaration.register_semantic.sysval_semantic = *tokens;
+}
+
+static void shader_sm4_read_dcl_indexable_temp(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.indexable_temp.register_idx = *tokens++;
+    ins->declaration.indexable_temp.register_size = *tokens++;
+    ins->declaration.indexable_temp.component_count = *tokens;
+}
+
+static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->flags = (opcode_token & VKD3D_SM4_GLOBAL_FLAGS_MASK) >> VKD3D_SM4_GLOBAL_FLAGS_SHIFT;
+}
+
+static void shader_sm5_read_fcall(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    priv->src_param[0].reg.u.fp_body_idx = *tokens++;
+    shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE, &priv->src_param[0]);
+}
+
+static void shader_sm5_read_dcl_function_body(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.index = *tokens;
+}
+
+static void shader_sm5_read_dcl_function_table(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.index = *tokens++;
+    FIXME("Ignoring set of function bodies (count %u).\n", *tokens);
+}
+
+static void shader_sm5_read_dcl_interface(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.fp.index = *tokens++;
+    ins->declaration.fp.body_count = *tokens++;
+    ins->declaration.fp.array_size = *tokens >> VKD3D_SM5_FP_ARRAY_SIZE_SHIFT;
+    ins->declaration.fp.table_count = *tokens++ & VKD3D_SM5_FP_TABLE_COUNT_MASK;
+    FIXME("Ignoring set of function tables (count %u).\n", ins->declaration.fp.table_count);
+}
+
+static void shader_sm5_read_control_point_count(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.count = (opcode_token & VKD3D_SM5_CONTROL_POINT_COUNT_MASK)
+            >> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT;
+}
+
+static void shader_sm5_read_dcl_tessellator_domain(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.tessellator_domain = (opcode_token & VKD3D_SM5_TESSELLATOR_MASK)
+        >> VKD3D_SM5_TESSELLATOR_SHIFT;
+}
+
+static void shader_sm5_read_dcl_tessellator_partitioning(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.tessellator_partitioning = (opcode_token & VKD3D_SM5_TESSELLATOR_MASK)
+            >> VKD3D_SM5_TESSELLATOR_SHIFT;
+}
+
+static void shader_sm5_read_dcl_tessellator_output_primitive(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.tessellator_output_primitive = (opcode_token & VKD3D_SM5_TESSELLATOR_MASK)
+            >> VKD3D_SM5_TESSELLATOR_SHIFT;
+}
+
+static void shader_sm5_read_dcl_hs_max_tessfactor(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.max_tessellation_factor = *(float *)tokens;
+}
+
+static void shader_sm5_read_dcl_thread_group(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->declaration.thread_group_size.x = *tokens++;
+    ins->declaration.thread_group_size.y = *tokens++;
+    ins->declaration.thread_group_size.z = *tokens++;
+}
+
+static void shader_sm5_read_dcl_uav_raw(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource;
+    const DWORD *end = &tokens[token_count];
+
+    shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UAV, &resource->resource.reg);
+    resource->resource.register_index = shader_sm4_map_resource_idx(&resource->resource.reg.reg, priv);
+    ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT;
+    shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.register_space);
+}
+
+static void shader_sm5_read_dcl_uav_structured(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource;
+    const DWORD *end = &tokens[token_count];
+
+    shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UAV, &resource->resource.reg);
+    resource->resource.register_index = shader_sm4_map_resource_idx(&resource->resource.reg.reg, priv);
+    ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT;
+    resource->byte_stride = *tokens++;
+    if (resource->byte_stride % 4)
+        FIXME("Byte stride %u is not multiple of 4.\n", resource->byte_stride);
+    shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.register_space);
+}
+
+static void shader_sm5_read_dcl_tgsm_raw(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, &ins->declaration.tgsm_raw.reg);
+    ins->declaration.tgsm_raw.byte_count = *tokens;
+    if (ins->declaration.tgsm_raw.byte_count % 4)
+        FIXME("Byte count %u is not multiple of 4.\n", ins->declaration.tgsm_raw.byte_count);
+}
+
+static void shader_sm5_read_dcl_tgsm_structured(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT,
+            &ins->declaration.tgsm_structured.reg);
+    ins->declaration.tgsm_structured.byte_stride = *tokens++;
+    ins->declaration.tgsm_structured.structure_count = *tokens;
+    if (ins->declaration.tgsm_structured.byte_stride % 4)
+        FIXME("Byte stride %u is not multiple of 4.\n", ins->declaration.tgsm_structured.byte_stride);
+}
+
+static void shader_sm5_read_dcl_resource_structured(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource;
+    const DWORD *end = &tokens[token_count];
+
+    shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_RESOURCE, &resource->resource.reg);
+    resource->resource.register_index = shader_sm4_map_resource_idx(&resource->resource.reg.reg, priv);
+    resource->byte_stride = *tokens++;
+    if (resource->byte_stride % 4)
+        FIXME("Byte stride %u is not multiple of 4.\n", resource->byte_stride);
+    shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.register_space);
+}
+
+static void shader_sm5_read_dcl_resource_raw(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource;
+    const DWORD *end = &tokens[token_count];
+
+    shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_RESOURCE, &resource->resource.reg);
+    resource->resource.register_index = shader_sm4_map_resource_idx(&resource->resource.reg.reg, priv);
+    shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.register_space);
+}
+
+static void shader_sm5_read_sync(struct vkd3d_shader_instruction *ins,
+        DWORD opcode, DWORD opcode_token, const DWORD *tokens, unsigned int token_count,
+        struct vkd3d_sm4_data *priv)
+{
+    ins->flags = (opcode_token & VKD3D_SM5_SYNC_FLAGS_MASK) >> VKD3D_SM5_SYNC_FLAGS_SHIFT;
+}
+
+/*
+ * f -> VKD3D_DATA_FLOAT
+ * i -> VKD3D_DATA_INT
+ * u -> VKD3D_DATA_UINT
+ * O -> VKD3D_DATA_OPAQUE
+ * R -> VKD3D_DATA_RESOURCE
+ * S -> VKD3D_DATA_SAMPLER
+ * U -> VKD3D_DATA_UAV
+ */
+static const struct vkd3d_sm4_opcode_info opcode_table[] =
+{
+    {VKD3D_SM4_OP_ADD,                              VKD3DSIH_ADD,                              "f",    "ff"},
+    {VKD3D_SM4_OP_AND,                              VKD3DSIH_AND,                              "u",    "uu"},
+    {VKD3D_SM4_OP_BREAK,                            VKD3DSIH_BREAK,                            "",     ""},
+    {VKD3D_SM4_OP_BREAKC,                           VKD3DSIH_BREAKP,                           "",     "u",
+            shader_sm4_read_conditional_op},
+    {VKD3D_SM4_OP_CASE,                             VKD3DSIH_CASE,                             "",     "u"},
+    {VKD3D_SM4_OP_CONTINUE,                         VKD3DSIH_CONTINUE,                         "",     ""},
+    {VKD3D_SM4_OP_CONTINUEC,                        VKD3DSIH_CONTINUEP,                        "",     "u",
+            shader_sm4_read_conditional_op},
+    {VKD3D_SM4_OP_CUT,                              VKD3DSIH_CUT,                              "",     ""},
+    {VKD3D_SM4_OP_DEFAULT,                          VKD3DSIH_DEFAULT,                          "",     ""},
+    {VKD3D_SM4_OP_DERIV_RTX,                        VKD3DSIH_DSX,                              "f",    "f"},
+    {VKD3D_SM4_OP_DERIV_RTY,                        VKD3DSIH_DSY,                              "f",    "f"},
+    {VKD3D_SM4_OP_DISCARD,                          VKD3DSIH_TEXKILL,                          "",     "u",
+            shader_sm4_read_conditional_op},
+    {VKD3D_SM4_OP_DIV,                              VKD3DSIH_DIV,                              "f",    "ff"},
+    {VKD3D_SM4_OP_DP2,                              VKD3DSIH_DP2,                              "f",    "ff"},
+    {VKD3D_SM4_OP_DP3,                              VKD3DSIH_DP3,                              "f",    "ff"},
+    {VKD3D_SM4_OP_DP4,                              VKD3DSIH_DP4,                              "f",    "ff"},
+    {VKD3D_SM4_OP_ELSE,                             VKD3DSIH_ELSE,                             "",     ""},
+    {VKD3D_SM4_OP_EMIT,                             VKD3DSIH_EMIT,                             "",     ""},
+    {VKD3D_SM4_OP_ENDIF,                            VKD3DSIH_ENDIF,                            "",     ""},
+    {VKD3D_SM4_OP_ENDLOOP,                          VKD3DSIH_ENDLOOP,                          "",     ""},
+    {VKD3D_SM4_OP_ENDSWITCH,                        VKD3DSIH_ENDSWITCH,                        "",     ""},
+    {VKD3D_SM4_OP_EQ,                               VKD3DSIH_EQ,                               "u",    "ff"},
+    {VKD3D_SM4_OP_EXP,                              VKD3DSIH_EXP,                              "f",    "f"},
+    {VKD3D_SM4_OP_FRC,                              VKD3DSIH_FRC,                              "f",    "f"},
+    {VKD3D_SM4_OP_FTOI,                             VKD3DSIH_FTOI,                             "i",    "f"},
+    {VKD3D_SM4_OP_FTOU,                             VKD3DSIH_FTOU,                             "u",    "f"},
+    {VKD3D_SM4_OP_GE,                               VKD3DSIH_GE,                               "u",    "ff"},
+    {VKD3D_SM4_OP_IADD,                             VKD3DSIH_IADD,                             "i",    "ii"},
+    {VKD3D_SM4_OP_IF,                               VKD3DSIH_IF,                               "",     "u",
+            shader_sm4_read_conditional_op},
+    {VKD3D_SM4_OP_IEQ,                              VKD3DSIH_IEQ,                              "u",    "ii"},
+    {VKD3D_SM4_OP_IGE,                              VKD3DSIH_IGE,                              "u",    "ii"},
+    {VKD3D_SM4_OP_ILT,                              VKD3DSIH_ILT,                              "u",    "ii"},
+    {VKD3D_SM4_OP_IMAD,                             VKD3DSIH_IMAD,                             "i",    "iii"},
+    {VKD3D_SM4_OP_IMAX,                             VKD3DSIH_IMAX,                             "i",    "ii"},
+    {VKD3D_SM4_OP_IMIN,                             VKD3DSIH_IMIN,                             "i",    "ii"},
+    {VKD3D_SM4_OP_IMUL,                             VKD3DSIH_IMUL,                             "ii",   "ii"},
+    {VKD3D_SM4_OP_INE,                              VKD3DSIH_INE,                              "u",    "ii"},
+    {VKD3D_SM4_OP_INEG,                             VKD3DSIH_INEG,                             "i",    "i"},
+    {VKD3D_SM4_OP_ISHL,                             VKD3DSIH_ISHL,                             "i",    "ii"},
+    {VKD3D_SM4_OP_ISHR,                             VKD3DSIH_ISHR,                             "i",    "ii"},
+    {VKD3D_SM4_OP_ITOF,                             VKD3DSIH_ITOF,                             "f",    "i"},
+    {VKD3D_SM4_OP_LABEL,                            VKD3DSIH_LABEL,                            "",     "O"},
+    {VKD3D_SM4_OP_LD,                               VKD3DSIH_LD,                               "u",    "iR"},
+    {VKD3D_SM4_OP_LD2DMS,                           VKD3DSIH_LD2DMS,                           "u",    "iRi"},
+    {VKD3D_SM4_OP_LOG,                              VKD3DSIH_LOG,                              "f",    "f"},
+    {VKD3D_SM4_OP_LOOP,                             VKD3DSIH_LOOP,                             "",     ""},
+    {VKD3D_SM4_OP_LT,                               VKD3DSIH_LT,                               "u",    "ff"},
+    {VKD3D_SM4_OP_MAD,                              VKD3DSIH_MAD,                              "f",    "fff"},
+    {VKD3D_SM4_OP_MIN,                              VKD3DSIH_MIN,                              "f",    "ff"},
+    {VKD3D_SM4_OP_MAX,                              VKD3DSIH_MAX,                              "f",    "ff"},
+    {VKD3D_SM4_OP_SHADER_DATA,                      VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER,    "",     "",
+            shader_sm4_read_shader_data},
+    {VKD3D_SM4_OP_MOV,                              VKD3DSIH_MOV,                              "f",    "f"},
+    {VKD3D_SM4_OP_MOVC,                             VKD3DSIH_MOVC,                             "f",    "uff"},
+    {VKD3D_SM4_OP_MUL,                              VKD3DSIH_MUL,                              "f",    "ff"},
+    {VKD3D_SM4_OP_NE,                               VKD3DSIH_NE,                               "u",    "ff"},
+    {VKD3D_SM4_OP_NOP,                              VKD3DSIH_NOP,                              "",     ""},
+    {VKD3D_SM4_OP_NOT,                              VKD3DSIH_NOT,                              "u",    "u"},
+    {VKD3D_SM4_OP_OR,                               VKD3DSIH_OR,                               "u",    "uu"},
+    {VKD3D_SM4_OP_RESINFO,                          VKD3DSIH_RESINFO,                          "f",    "iR"},
+    {VKD3D_SM4_OP_RET,                              VKD3DSIH_RET,                              "",     ""},
+    {VKD3D_SM4_OP_RETC,                             VKD3DSIH_RETP,                             "",     "u",
+            shader_sm4_read_conditional_op},
+    {VKD3D_SM4_OP_ROUND_NE,                         VKD3DSIH_ROUND_NE,                         "f",    "f"},
+    {VKD3D_SM4_OP_ROUND_NI,                         VKD3DSIH_ROUND_NI,                         "f",    "f"},
+    {VKD3D_SM4_OP_ROUND_PI,                         VKD3DSIH_ROUND_PI,                         "f",    "f"},
+    {VKD3D_SM4_OP_ROUND_Z,                          VKD3DSIH_ROUND_Z,                          "f",    "f"},
+    {VKD3D_SM4_OP_RSQ,                              VKD3DSIH_RSQ,                              "f",    "f"},
+    {VKD3D_SM4_OP_SAMPLE,                           VKD3DSIH_SAMPLE,                           "u",    "fRS"},
+    {VKD3D_SM4_OP_SAMPLE_C,                         VKD3DSIH_SAMPLE_C,                         "f",    "fRSf"},
+    {VKD3D_SM4_OP_SAMPLE_C_LZ,                      VKD3DSIH_SAMPLE_C_LZ,                      "f",    "fRSf"},
+    {VKD3D_SM4_OP_SAMPLE_LOD,                       VKD3DSIH_SAMPLE_LOD,                       "u",    "fRSf"},
+    {VKD3D_SM4_OP_SAMPLE_GRAD,                      VKD3DSIH_SAMPLE_GRAD,                      "u",    "fRSff"},
+    {VKD3D_SM4_OP_SAMPLE_B,                         VKD3DSIH_SAMPLE_B,                         "u",    "fRSf"},
+    {VKD3D_SM4_OP_SQRT,                             VKD3DSIH_SQRT,                             "f",    "f"},
+    {VKD3D_SM4_OP_SWITCH,                           VKD3DSIH_SWITCH,                           "",     "i"},
+    {VKD3D_SM4_OP_SINCOS,                           VKD3DSIH_SINCOS,                           "ff",   "f"},
+    {VKD3D_SM4_OP_UDIV,                             VKD3DSIH_UDIV,                             "uu",   "uu"},
+    {VKD3D_SM4_OP_ULT,                              VKD3DSIH_ULT,                              "u",    "uu"},
+    {VKD3D_SM4_OP_UGE,                              VKD3DSIH_UGE,                              "u",    "uu"},
+    {VKD3D_SM4_OP_UMUL,                             VKD3DSIH_UMUL,                             "uu",   "uu"},
+    {VKD3D_SM4_OP_UMAX,                             VKD3DSIH_UMAX,                             "u",    "uu"},
+    {VKD3D_SM4_OP_UMIN,                             VKD3DSIH_UMIN,                             "u",    "uu"},
+    {VKD3D_SM4_OP_USHR,                             VKD3DSIH_USHR,                             "u",    "uu"},
+    {VKD3D_SM4_OP_UTOF,                             VKD3DSIH_UTOF,                             "f",    "u"},
+    {VKD3D_SM4_OP_XOR,                              VKD3DSIH_XOR,                              "u",    "uu"},
+    {VKD3D_SM4_OP_DCL_RESOURCE,                     VKD3DSIH_DCL,                              "R",    "",
+            shader_sm4_read_dcl_resource},
+    {VKD3D_SM4_OP_DCL_CONSTANT_BUFFER,              VKD3DSIH_DCL_CONSTANT_BUFFER,              "",     "",
+            shader_sm4_read_dcl_constant_buffer},
+    {VKD3D_SM4_OP_DCL_SAMPLER,                      VKD3DSIH_DCL_SAMPLER,                      "",     "",
+            shader_sm4_read_dcl_sampler},
+    {VKD3D_SM4_OP_DCL_INDEX_RANGE,                  VKD3DSIH_DCL_INDEX_RANGE,                  "",     "",
+            shader_sm4_read_dcl_index_range},
+    {VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY,              VKD3DSIH_DCL_OUTPUT_TOPOLOGY,              "",     "",
+            shader_sm4_read_dcl_output_topology},
+    {VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE,              VKD3DSIH_DCL_INPUT_PRIMITIVE,              "",     "",
+            shader_sm4_read_dcl_input_primitive},
+    {VKD3D_SM4_OP_DCL_VERTICES_OUT,                 VKD3DSIH_DCL_VERTICES_OUT,                 "",     "",
+            shader_sm4_read_declaration_count},
+    {VKD3D_SM4_OP_DCL_INPUT,                        VKD3DSIH_DCL_INPUT,                        "",     "",
+            shader_sm4_read_declaration_dst},
+    {VKD3D_SM4_OP_DCL_INPUT_SGV,                    VKD3DSIH_DCL_INPUT_SGV,                    "",     "",
+            shader_sm4_read_declaration_register_semantic},
+    {VKD3D_SM4_OP_DCL_INPUT_SIV,                    VKD3DSIH_DCL_INPUT_SIV,                    "",     "",
+            shader_sm4_read_declaration_register_semantic},
+    {VKD3D_SM4_OP_DCL_INPUT_PS,                     VKD3DSIH_DCL_INPUT_PS,                     "",     "",
+            shader_sm4_read_dcl_input_ps},
+    {VKD3D_SM4_OP_DCL_INPUT_PS_SGV,                 VKD3DSIH_DCL_INPUT_PS_SGV,                 "",     "",
+            shader_sm4_read_declaration_register_semantic},
+    {VKD3D_SM4_OP_DCL_INPUT_PS_SIV,                 VKD3DSIH_DCL_INPUT_PS_SIV,                 "",     "",
+            shader_sm4_read_dcl_input_ps_siv},
+    {VKD3D_SM4_OP_DCL_OUTPUT,                       VKD3DSIH_DCL_OUTPUT,                       "",     "",
+            shader_sm4_read_declaration_dst},
+    {VKD3D_SM4_OP_DCL_OUTPUT_SIV,                   VKD3DSIH_DCL_OUTPUT_SIV,                   "",     "",
+            shader_sm4_read_declaration_register_semantic},
+    {VKD3D_SM4_OP_DCL_TEMPS,                        VKD3DSIH_DCL_TEMPS,                        "",     "",
+            shader_sm4_read_declaration_count},
+    {VKD3D_SM4_OP_DCL_INDEXABLE_TEMP,               VKD3DSIH_DCL_INDEXABLE_TEMP,               "",     "",
+            shader_sm4_read_dcl_indexable_temp},
+    {VKD3D_SM4_OP_DCL_GLOBAL_FLAGS,                 VKD3DSIH_DCL_GLOBAL_FLAGS,                 "",     "",
+            shader_sm4_read_dcl_global_flags},
+    {VKD3D_SM4_OP_LOD,                              VKD3DSIH_LOD,                              "f",    "fRS"},
+    {VKD3D_SM4_OP_GATHER4,                          VKD3DSIH_GATHER4,                          "u",    "fRS"},
+    {VKD3D_SM4_OP_SAMPLE_POS,                       VKD3DSIH_SAMPLE_POS,                       "f",    "Ru"},
+    {VKD3D_SM4_OP_SAMPLE_INFO,                      VKD3DSIH_SAMPLE_INFO,                      "f",    "R"},
+    {VKD3D_SM5_OP_HS_DECLS,                         VKD3DSIH_HS_DECLS,                         "",     ""},
+    {VKD3D_SM5_OP_HS_CONTROL_POINT_PHASE,           VKD3DSIH_HS_CONTROL_POINT_PHASE,           "",     ""},
+    {VKD3D_SM5_OP_HS_FORK_PHASE,                    VKD3DSIH_HS_FORK_PHASE,                    "",     ""},
+    {VKD3D_SM5_OP_HS_JOIN_PHASE,                    VKD3DSIH_HS_JOIN_PHASE,                    "",     ""},
+    {VKD3D_SM5_OP_EMIT_STREAM,                      VKD3DSIH_EMIT_STREAM,                      "",     "f"},
+    {VKD3D_SM5_OP_CUT_STREAM,                       VKD3DSIH_CUT_STREAM,                       "",     "f"},
+    {VKD3D_SM5_OP_FCALL,                            VKD3DSIH_FCALL,                            "",     "O",
+            shader_sm5_read_fcall},
+    {VKD3D_SM5_OP_BUFINFO,                          VKD3DSIH_BUFINFO,                          "i",    "U"},
+    {VKD3D_SM5_OP_DERIV_RTX_COARSE,                 VKD3DSIH_DSX_COARSE,                       "f",    "f"},
+    {VKD3D_SM5_OP_DERIV_RTX_FINE,                   VKD3DSIH_DSX_FINE,                         "f",    "f"},
+    {VKD3D_SM5_OP_DERIV_RTY_COARSE,                 VKD3DSIH_DSY_COARSE,                       "f",    "f"},
+    {VKD3D_SM5_OP_DERIV_RTY_FINE,                   VKD3DSIH_DSY_FINE,                         "f",    "f"},
+    {VKD3D_SM5_OP_GATHER4_C,                        VKD3DSIH_GATHER4_C,                        "f",    "fRSf"},
+    {VKD3D_SM5_OP_GATHER4_PO,                       VKD3DSIH_GATHER4_PO,                       "f",    "fiRS"},
+    {VKD3D_SM5_OP_GATHER4_PO_C,                     VKD3DSIH_GATHER4_PO_C,                     "f",    "fiRSf"},
+    {VKD3D_SM5_OP_RCP,                              VKD3DSIH_RCP,                              "f",    "f"},
+    {VKD3D_SM5_OP_F32TOF16,                         VKD3DSIH_F32TOF16,                         "u",    "f"},
+    {VKD3D_SM5_OP_F16TOF32,                         VKD3DSIH_F16TOF32,                         "f",    "u"},
+    {VKD3D_SM5_OP_COUNTBITS,                        VKD3DSIH_COUNTBITS,                        "u",    "u"},
+    {VKD3D_SM5_OP_FIRSTBIT_HI,                      VKD3DSIH_FIRSTBIT_HI,                      "u",    "u"},
+    {VKD3D_SM5_OP_FIRSTBIT_LO,                      VKD3DSIH_FIRSTBIT_LO,                      "u",    "u"},
+    {VKD3D_SM5_OP_FIRSTBIT_SHI,                     VKD3DSIH_FIRSTBIT_SHI,                     "u",    "i"},
+    {VKD3D_SM5_OP_UBFE,                             VKD3DSIH_UBFE,                             "u",    "iiu"},
+    {VKD3D_SM5_OP_IBFE,                             VKD3DSIH_IBFE,                             "i",    "iii"},
+    {VKD3D_SM5_OP_BFI,                              VKD3DSIH_BFI,                              "u",    "iiuu"},
+    {VKD3D_SM5_OP_BFREV,                            VKD3DSIH_BFREV,                            "u",    "u"},
+    {VKD3D_SM5_OP_SWAPC,                            VKD3DSIH_SWAPC,                            "ff",   "uff"},
+    {VKD3D_SM5_OP_DCL_STREAM,                       VKD3DSIH_DCL_STREAM,                       "",     "O"},
+    {VKD3D_SM5_OP_DCL_FUNCTION_BODY,                VKD3DSIH_DCL_FUNCTION_BODY,                "",     "",
+            shader_sm5_read_dcl_function_body},
+    {VKD3D_SM5_OP_DCL_FUNCTION_TABLE,               VKD3DSIH_DCL_FUNCTION_TABLE,               "",     "",
+            shader_sm5_read_dcl_function_table},
+    {VKD3D_SM5_OP_DCL_INTERFACE,                    VKD3DSIH_DCL_INTERFACE,                    "",     "",
+            shader_sm5_read_dcl_interface},
+    {VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT,    VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT,    "",     "",
+            shader_sm5_read_control_point_count},
+    {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT,   VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT,   "",     "",
+            shader_sm5_read_control_point_count},
+    {VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN,           VKD3DSIH_DCL_TESSELLATOR_DOMAIN,           "",     "",
+            shader_sm5_read_dcl_tessellator_domain},
+    {VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING,     VKD3DSIH_DCL_TESSELLATOR_PARTITIONING,     "",     "",
+            shader_sm5_read_dcl_tessellator_partitioning},
+    {VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, "",     "",
+            shader_sm5_read_dcl_tessellator_output_primitive},
+    {VKD3D_SM5_OP_DCL_HS_MAX_TESSFACTOR,            VKD3DSIH_DCL_HS_MAX_TESSFACTOR,            "",     "",
+            shader_sm5_read_dcl_hs_max_tessfactor},
+    {VKD3D_SM5_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT, VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT, "",     "",
+            shader_sm4_read_declaration_count},
+    {VKD3D_SM5_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT, VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT, "",     "",
+            shader_sm4_read_declaration_count},
+    {VKD3D_SM5_OP_DCL_THREAD_GROUP,                 VKD3DSIH_DCL_THREAD_GROUP,                 "",     "",
+            shader_sm5_read_dcl_thread_group},
+    {VKD3D_SM5_OP_DCL_UAV_TYPED,                    VKD3DSIH_DCL_UAV_TYPED,                    "",     "",
+            shader_sm4_read_dcl_resource},
+    {VKD3D_SM5_OP_DCL_UAV_RAW,                      VKD3DSIH_DCL_UAV_RAW,                      "",     "",
+            shader_sm5_read_dcl_uav_raw},
+    {VKD3D_SM5_OP_DCL_UAV_STRUCTURED,               VKD3DSIH_DCL_UAV_STRUCTURED,               "",     "",
+            shader_sm5_read_dcl_uav_structured},
+    {VKD3D_SM5_OP_DCL_TGSM_RAW,                     VKD3DSIH_DCL_TGSM_RAW,                     "",     "",
+            shader_sm5_read_dcl_tgsm_raw},
+    {VKD3D_SM5_OP_DCL_TGSM_STRUCTURED,              VKD3DSIH_DCL_TGSM_STRUCTURED,              "",     "",
+            shader_sm5_read_dcl_tgsm_structured},
+    {VKD3D_SM5_OP_DCL_RESOURCE_RAW,                 VKD3DSIH_DCL_RESOURCE_RAW,                 "",     "",
+            shader_sm5_read_dcl_resource_raw},
+    {VKD3D_SM5_OP_DCL_RESOURCE_STRUCTURED,          VKD3DSIH_DCL_RESOURCE_STRUCTURED,          "",     "",
+            shader_sm5_read_dcl_resource_structured},
+    {VKD3D_SM5_OP_LD_UAV_TYPED,                     VKD3DSIH_LD_UAV_TYPED,                     "u",    "iU"},
+    {VKD3D_SM5_OP_STORE_UAV_TYPED,                  VKD3DSIH_STORE_UAV_TYPED,                  "U",    "iu"},
+    {VKD3D_SM5_OP_LD_RAW,                           VKD3DSIH_LD_RAW,                           "u",    "iU"},
+    {VKD3D_SM5_OP_STORE_RAW,                        VKD3DSIH_STORE_RAW,                        "U",    "uu"},
+    {VKD3D_SM5_OP_LD_STRUCTURED,                    VKD3DSIH_LD_STRUCTURED,                    "u",    "iiR"},
+    {VKD3D_SM5_OP_STORE_STRUCTURED,                 VKD3DSIH_STORE_STRUCTURED,                 "U",    "iiu"},
+    {VKD3D_SM5_OP_ATOMIC_AND,                       VKD3DSIH_ATOMIC_AND,                       "U",    "iu"},
+    {VKD3D_SM5_OP_ATOMIC_OR,                        VKD3DSIH_ATOMIC_OR,                        "U",    "iu"},
+    {VKD3D_SM5_OP_ATOMIC_XOR,                       VKD3DSIH_ATOMIC_XOR,                       "U",    "iu"},
+    {VKD3D_SM5_OP_ATOMIC_CMP_STORE,                 VKD3DSIH_ATOMIC_CMP_STORE,                 "U",    "iuu"},
+    {VKD3D_SM5_OP_ATOMIC_IADD,                      VKD3DSIH_ATOMIC_IADD,                      "U",    "ii"},
+    {VKD3D_SM5_OP_ATOMIC_IMAX,                      VKD3DSIH_ATOMIC_IMAX,                      "U",    "ii"},
+    {VKD3D_SM5_OP_ATOMIC_IMIN,                      VKD3DSIH_ATOMIC_IMIN,                      "U",    "ii"},
+    {VKD3D_SM5_OP_ATOMIC_UMAX,                      VKD3DSIH_ATOMIC_UMAX,                      "U",    "iu"},
+    {VKD3D_SM5_OP_ATOMIC_UMIN,                      VKD3DSIH_ATOMIC_UMIN,                      "U",    "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC,                 VKD3DSIH_IMM_ATOMIC_ALLOC,                 "u",    "U"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME,               VKD3DSIH_IMM_ATOMIC_CONSUME,               "u",    "U"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_IADD,                  VKD3DSIH_IMM_ATOMIC_IADD,                  "uU",   "ii"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_AND,                   VKD3DSIH_IMM_ATOMIC_AND,                   "uU",   "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_OR,                    VKD3DSIH_IMM_ATOMIC_OR,                    "uU",   "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_XOR,                   VKD3DSIH_IMM_ATOMIC_XOR,                   "uU",   "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_EXCH,                  VKD3DSIH_IMM_ATOMIC_EXCH,                  "uU",   "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH,              VKD3DSIH_IMM_ATOMIC_CMP_EXCH,              "uU",   "iuu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_IMAX,                  VKD3DSIH_IMM_ATOMIC_IMAX,                  "iU",   "ii"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_IMIN,                  VKD3DSIH_IMM_ATOMIC_IMIN,                  "iU",   "ii"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_UMAX,                  VKD3DSIH_IMM_ATOMIC_UMAX,                  "uU",   "iu"},
+    {VKD3D_SM5_OP_IMM_ATOMIC_UMIN,                  VKD3DSIH_IMM_ATOMIC_UMIN,                  "uU",   "iu"},
+    {VKD3D_SM5_OP_SYNC,                             VKD3DSIH_SYNC,                             "",     "",
+            shader_sm5_read_sync},
+    {VKD3D_SM5_OP_EVAL_SAMPLE_INDEX,                VKD3DSIH_EVAL_SAMPLE_INDEX,                "f",    "fi"},
+    {VKD3D_SM5_OP_EVAL_CENTROID,                    VKD3DSIH_EVAL_CENTROID,                    "f",    "f"},
+    {VKD3D_SM5_OP_DCL_GS_INSTANCES,                 VKD3DSIH_DCL_GS_INSTANCES,                 "",     "",
+            shader_sm4_read_declaration_count},
+};
+
+static const enum vkd3d_shader_register_type register_type_table[] =
+{
+    /* VKD3D_SM4_RT_TEMP */                    VKD3DSPR_TEMP,
+    /* VKD3D_SM4_RT_INPUT */                   VKD3DSPR_INPUT,
+    /* VKD3D_SM4_RT_OUTPUT */                  VKD3DSPR_OUTPUT,
+    /* VKD3D_SM4_RT_INDEXABLE_TEMP */          VKD3DSPR_IDXTEMP,
+    /* VKD3D_SM4_RT_IMMCONST */                VKD3DSPR_IMMCONST,
+    /* UNKNOWN */                              ~0u,
+    /* VKD3D_SM4_RT_SAMPLER */                 VKD3DSPR_SAMPLER,
+    /* VKD3D_SM4_RT_RESOURCE */                VKD3DSPR_RESOURCE,
+    /* VKD3D_SM4_RT_CONSTBUFFER */             VKD3DSPR_CONSTBUFFER,
+    /* VKD3D_SM4_RT_IMMCONSTBUFFER */          VKD3DSPR_IMMCONSTBUFFER,
+    /* UNKNOWN */                              ~0u,
+    /* VKD3D_SM4_RT_PRIMID */                  VKD3DSPR_PRIMID,
+    /* VKD3D_SM4_RT_DEPTHOUT */                VKD3DSPR_DEPTHOUT,
+    /* VKD3D_SM4_RT_NULL */                    VKD3DSPR_NULL,
+    /* VKD3D_SM4_RT_RASTERIZER */              VKD3DSPR_RASTERIZER,
+    /* VKD3D_SM4_RT_OMASK */                   VKD3DSPR_SAMPLEMASK,
+    /* VKD3D_SM5_RT_STREAM */                  VKD3DSPR_STREAM,
+    /* VKD3D_SM5_RT_FUNCTION_BODY */           VKD3DSPR_FUNCTIONBODY,
+    /* UNKNOWN */                              ~0u,
+    /* VKD3D_SM5_RT_FUNCTION_POINTER */        VKD3DSPR_FUNCTIONPOINTER,
+    /* UNKNOWN */                              ~0u,
+    /* UNKNOWN */                              ~0u,
+    /* VKD3D_SM5_RT_OUTPUT_CONTROL_POINT_ID */ VKD3DSPR_OUTPOINTID,
+    /* VKD3D_SM5_RT_FORK_INSTANCE_ID */        VKD3DSPR_FORKINSTID,
+    /* VKD3D_SM5_RT_JOIN_INSTANCE_ID */        VKD3DSPR_JOININSTID,
+    /* VKD3D_SM5_RT_INPUT_CONTROL_POINT */     VKD3DSPR_INCONTROLPOINT,
+    /* VKD3D_SM5_RT_OUTPUT_CONTROL_POINT */    VKD3DSPR_OUTCONTROLPOINT,
+    /* VKD3D_SM5_RT_PATCH_CONSTANT_DATA */     VKD3DSPR_PATCHCONST,
+    /* VKD3D_SM5_RT_DOMAIN_LOCATION */         VKD3DSPR_TESSCOORD,
+    /* UNKNOWN */                              ~0u,
+    /* VKD3D_SM5_RT_UAV */                     VKD3DSPR_UAV,
+    /* VKD3D_SM5_RT_SHARED_MEMORY */           VKD3DSPR_GROUPSHAREDMEM,
+    /* VKD3D_SM5_RT_THREAD_ID */               VKD3DSPR_THREADID,
+    /* VKD3D_SM5_RT_THREAD_GROUP_ID */         VKD3DSPR_THREADGROUPID,
+    /* VKD3D_SM5_RT_LOCAL_THREAD_ID */         VKD3DSPR_LOCALTHREADID,
+    /* VKD3D_SM5_RT_COVERAGE */                VKD3DSPR_COVERAGE,
+    /* VKD3D_SM5_RT_LOCAL_THREAD_INDEX */      VKD3DSPR_LOCALTHREADINDEX,
+    /* VKD3D_SM5_RT_GS_INSTANCE_ID */          VKD3DSPR_GSINSTID,
+    /* VKD3D_SM5_RT_DEPTHOUT_GREATER_EQUAL */  VKD3DSPR_DEPTHOUTGE,
+    /* VKD3D_SM5_RT_DEPTHOUT_LESS_EQUAL */     VKD3DSPR_DEPTHOUTLE,
+};
+
+static const struct vkd3d_sm4_opcode_info *get_opcode_info(enum vkd3d_sm4_opcode opcode)
+{
+    unsigned int i;
+
+    for (i = 0; i < sizeof(opcode_table) / sizeof(*opcode_table); ++i)
+    {
+        if (opcode == opcode_table[i].opcode) return &opcode_table[i];
+    }
+
+    return NULL;
+}
+
+static void map_register(const struct vkd3d_sm4_data *priv, struct vkd3d_shader_register *reg)
+{
+    switch (priv->shader_version.type)
+    {
+        case VKD3D_SHADER_TYPE_PIXEL:
+            if (reg->type == VKD3DSPR_OUTPUT)
+            {
+                unsigned int reg_idx = reg->idx[0].offset;
+
+                if (reg_idx >= ARRAY_SIZE(priv->output_map))
+                {
+                    ERR("Invalid output index %u.\n", reg_idx);
+                    break;
+                }
+
+                reg->type = VKD3DSPR_COLOROUT;
+                reg->idx[0].offset = priv->output_map[reg_idx];
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static enum vkd3d_data_type map_data_type(char t)
+{
+    switch (t)
+    {
+        case 'f':
+            return VKD3D_DATA_FLOAT;
+        case 'i':
+            return VKD3D_DATA_INT;
+        case 'u':
+            return VKD3D_DATA_UINT;
+        case 'O':
+            return VKD3D_DATA_OPAQUE;
+        case 'R':
+            return VKD3D_DATA_RESOURCE;
+        case 'S':
+            return VKD3D_DATA_SAMPLER;
+        case 'U':
+            return VKD3D_DATA_UAV;
+        default:
+            ERR("Invalid data type '%c'.\n", t);
+            return VKD3D_DATA_FLOAT;
+    }
+}
+
+void *shader_sm4_init(const DWORD *byte_code, size_t byte_code_size,
+        const struct vkd3d_shader_signature *output_signature)
+{
+    DWORD version_token, token_count;
+    struct vkd3d_sm4_data *priv;
+    unsigned int i;
+
+    if (byte_code_size / sizeof(*byte_code) < 2)
+    {
+        WARN("Invalid byte code size %lu.\n", (long)byte_code_size);
+        return NULL;
+    }
+
+    version_token = byte_code[0];
+    TRACE("Version: 0x%08x.\n", version_token);
+    token_count = byte_code[1];
+    TRACE("Token count: %u.\n", token_count);
+
+    if (token_count < 2 || byte_code_size / sizeof(*byte_code) < token_count)
+    {
+        WARN("Invalid token count %u.\n", token_count);
+        return NULL;
+    }
+
+    if (!(priv = vkd3d_malloc(sizeof(*priv))))
+    {
+        ERR("Failed to allocate private data\n");
+        return NULL;
+    }
+
+    priv->start = &byte_code[2];
+    priv->end = &byte_code[token_count];
+
+    switch (version_token >> 16)
+    {
+        case VKD3D_SM4_PS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_PIXEL;
+            break;
+
+        case VKD3D_SM4_VS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_VERTEX;
+            break;
+
+        case VKD3D_SM4_GS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_GEOMETRY;
+            break;
+
+        case VKD3D_SM5_HS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_HULL;
+            break;
+
+        case VKD3D_SM5_DS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_DOMAIN;
+            break;
+
+        case VKD3D_SM5_CS:
+            priv->shader_version.type = VKD3D_SHADER_TYPE_COMPUTE;
+            break;
+
+        default:
+            FIXME("Unrecognised shader type %#x.\n", version_token >> 16);
+    }
+    priv->shader_version.major = VKD3D_SM4_VERSION_MAJOR(version_token);
+    priv->shader_version.minor = VKD3D_SM4_VERSION_MINOR(version_token);
+
+    memset(priv->output_map, 0xff, sizeof(priv->output_map));
+    for (i = 0; i < output_signature->element_count; ++i)
+    {
+        struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
+
+        if (e->register_index >= ARRAY_SIZE(priv->output_map))
+        {
+            WARN("Invalid output index %u.\n", e->register_index);
+            continue;
+        }
+
+        priv->output_map[e->register_index] = e->semantic_index;
+    }
+
+    list_init(&priv->src_free);
+    list_init(&priv->src);
+
+    return priv;
+}
+
+void shader_sm4_free(void *data)
+{
+    struct vkd3d_shader_src_param_entry *e1, *e2;
+    struct vkd3d_sm4_data *priv = data;
+
+    list_move_head(&priv->src_free, &priv->src);
+    LIST_FOR_EACH_ENTRY_SAFE(e1, e2, &priv->src_free, struct vkd3d_shader_src_param_entry, entry)
+    {
+        vkd3d_free(e1);
+    }
+    vkd3d_free(priv);
+}
+
+static struct vkd3d_shader_src_param *get_src_param(struct vkd3d_sm4_data *priv)
+{
+    struct vkd3d_shader_src_param_entry *e;
+    struct list *elem;
+
+    if (!list_empty(&priv->src_free))
+    {
+        elem = list_head(&priv->src_free);
+        list_remove(elem);
+    }
+    else
+    {
+        if (!(e = vkd3d_malloc(sizeof(*e))))
+            return NULL;
+        elem = &e->entry;
+    }
+
+    list_add_tail(&priv->src, elem);
+    e = LIST_ENTRY(elem, struct vkd3d_shader_src_param_entry, entry);
+    return &e->param;
+}
+
+void shader_sm4_read_header(void *data, const DWORD **ptr, struct vkd3d_shader_version *shader_version)
+{
+    struct vkd3d_sm4_data *priv = data;
+
+    *ptr = priv->start;
+    *shader_version = priv->shader_version;
+}
+
+static bool shader_sm4_read_reg_idx(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        DWORD addressing, struct vkd3d_shader_register_index *reg_idx)
+{
+    if (addressing & VKD3D_SM4_ADDRESSING_RELATIVE)
+    {
+        struct vkd3d_shader_src_param *rel_addr = get_src_param(priv);
+
+        if (!(reg_idx->rel_addr = rel_addr))
+        {
+            ERR("Failed to get src param for relative addressing.\n");
+            return false;
+        }
+
+        if (addressing & VKD3D_SM4_ADDRESSING_OFFSET)
+            reg_idx->offset = *(*ptr)++;
+        else
+            reg_idx->offset = 0;
+        shader_sm4_read_src_param(priv, ptr, end, VKD3D_DATA_INT, rel_addr);
+    }
+    else
+    {
+        reg_idx->rel_addr = NULL;
+        reg_idx->offset = *(*ptr)++;
+    }
+
+    return true;
+}
+
+static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        enum vkd3d_data_type data_type, struct vkd3d_shader_register *param,
+        enum vkd3d_shader_src_modifier *modifier)
+{
+    enum vkd3d_sm4_register_type register_type;
+    DWORD token, order;
+
+    if (*ptr >= end)
+    {
+        WARN("Invalid ptr %p >= end %p.\n", *ptr, end);
+        return false;
+    }
+    token = *(*ptr)++;
+
+    register_type = (token & VKD3D_SM4_REGISTER_TYPE_MASK) >> VKD3D_SM4_REGISTER_TYPE_SHIFT;
+    if (register_type >= ARRAY_SIZE(register_type_table)
+            || register_type_table[register_type] == VKD3DSPR_INVALID)
+    {
+        FIXME("Unhandled register type %#x.\n", register_type);
+        param->type = VKD3DSPR_TEMP;
+    }
+    else
+    {
+        param->type = register_type_table[register_type];
+    }
+    param->data_type = data_type;
+
+    if (token & VKD3D_SM4_REGISTER_MODIFIER)
+    {
+        DWORD m;
+
+        if (*ptr >= end)
+        {
+            WARN("Invalid ptr %p >= end %p.\n", *ptr, end);
+            return false;
+        }
+        m = *(*ptr)++;
+
+        switch (m)
+        {
+            case 0x41:
+                *modifier = VKD3DSPSM_NEG;
+                break;
+
+            case 0x81:
+                *modifier = VKD3DSPSM_ABS;
+                break;
+
+            case 0xc1:
+                *modifier = VKD3DSPSM_ABSNEG;
+                break;
+
+            default:
+                FIXME("Skipping modifier 0x%08x.\n", m);
+                *modifier = VKD3DSPSM_NONE;
+                break;
+        }
+    }
+    else
+    {
+        *modifier = VKD3DSPSM_NONE;
+    }
+
+    order = (token & VKD3D_SM4_REGISTER_ORDER_MASK) >> VKD3D_SM4_REGISTER_ORDER_SHIFT;
+
+    if (order < 1)
+    {
+        param->idx[0].offset = ~0u;
+        param->idx[0].rel_addr = NULL;
+    }
+    else
+    {
+        DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK0) >> VKD3D_SM4_ADDRESSING_SHIFT0;
+        if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[0])))
+        {
+            ERR("Failed to read register index.\n");
+            return false;
+        }
+    }
+
+    if (order < 2)
+    {
+        param->idx[1].offset = ~0u;
+        param->idx[1].rel_addr = NULL;
+    }
+    else
+    {
+        DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK1) >> VKD3D_SM4_ADDRESSING_SHIFT1;
+        if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[1])))
+        {
+            ERR("Failed to read register index.\n");
+            return false;
+        }
+    }
+
+    if (order < 3)
+    {
+        param->idx[2].offset = ~0u;
+        param->idx[2].rel_addr = NULL;
+    }
+    else
+    {
+        DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2;
+        if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[2])))
+        {
+            ERR("Failed to read register index.\n");
+            return false;
+        }
+    }
+
+    if (order > 3)
+    {
+        WARN("Unhandled order %u.\n", order);
+        return false;
+    }
+
+    if (register_type == VKD3D_SM4_RT_IMMCONST)
+    {
+        enum vkd3d_sm4_dimension dimension = (token & VKD3D_SM4_DIMENSION_MASK) >> VKD3D_SM4_DIMENSION_SHIFT;
+
+        switch (dimension)
+        {
+            case VKD3D_SM4_DIMENSION_SCALAR:
+                param->immconst_type = VKD3D_IMMCONST_SCALAR;
+                if (end - *ptr < 1)
+                {
+                    WARN("Invalid ptr %p, end %p.\n", *ptr, end);
+                    return false;
+                }
+                memcpy(param->u.immconst_uint, *ptr, 1 * sizeof(DWORD));
+                *ptr += 1;
+                break;
+
+            case VKD3D_SM4_DIMENSION_VEC4:
+                param->immconst_type = VKD3D_IMMCONST_VEC4;
+                if (end - *ptr < VKD3D_VEC4_SIZE)
+                {
+                    WARN("Invalid ptr %p, end %p.\n", *ptr, end);
+                    return false;
+                }
+                memcpy(param->u.immconst_uint, *ptr, VKD3D_VEC4_SIZE * sizeof(DWORD));
+                *ptr += 4;
+                break;
+
+            default:
+                FIXME("Unhandled dimension %#x.\n", dimension);
+                break;
+        }
+    }
+    else if (register_type == VKD3D_SM4_RT_CONSTBUFFER && order == 2)
+    {
+        /* SM5.1 places the buffer offset in idx[2]; earlier versions place it
+         * in idx[1]. Normalize to SM5.1. */
+        param->idx[2] = param->idx[1];
+        param->idx[1].rel_addr = NULL;
+        param->idx[1].offset = 0;
+    }
+
+    map_register(priv, param);
+
+    return true;
+}
+
+static bool shader_sm4_is_scalar_register(const struct vkd3d_shader_register *reg)
+{
+    switch (reg->type)
+    {
+        case VKD3DSPR_COVERAGE:
+        case VKD3DSPR_DEPTHOUT:
+        case VKD3DSPR_DEPTHOUTGE:
+        case VKD3DSPR_DEPTHOUTLE:
+        case VKD3DSPR_GSINSTID:
+        case VKD3DSPR_LOCALTHREADINDEX:
+        case VKD3DSPR_OUTPOINTID:
+        case VKD3DSPR_PRIMID:
+        case VKD3DSPR_SAMPLEMASK:
+            return true;
+        default:
+            return false;
+    }
+}
+
+static uint32_t swizzle_from_sm4(uint32_t s)
+{
+    return vkd3d_shader_create_swizzle(s & 0x3, (s >> 2) & 0x3, (s >> 4) & 0x3, (s >> 6) & 0x3);
+}
+
+static bool shader_sm4_read_src_param(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        enum vkd3d_data_type data_type, struct vkd3d_shader_src_param *src_param)
+{
+    DWORD token;
+
+    if (*ptr >= end)
+    {
+        WARN("Invalid ptr %p >= end %p.\n", *ptr, end);
+        return false;
+    }
+    token = **ptr;
+
+    if (!shader_sm4_read_param(priv, ptr, end, data_type, &src_param->reg, &src_param->modifiers))
+    {
+        ERR("Failed to read parameter.\n");
+        return false;
+    }
+
+    if (src_param->reg.type == VKD3DSPR_IMMCONST)
+    {
+        src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE;
+    }
+    else
+    {
+        enum vkd3d_sm4_swizzle_type swizzle_type =
+                (token & VKD3D_SM4_SWIZZLE_TYPE_MASK) >> VKD3D_SM4_SWIZZLE_TYPE_SHIFT;
+
+        switch (swizzle_type)
+        {
+            case VKD3D_SM4_SWIZZLE_NONE:
+                if (shader_sm4_is_scalar_register(&src_param->reg))
+                    src_param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
+                else
+                    src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE;
+                break;
+
+            case VKD3D_SM4_SWIZZLE_SCALAR:
+                src_param->swizzle = (token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT;
+                src_param->swizzle = (src_param->swizzle & 0x3) * 0x01010101;
+                break;
+
+            case VKD3D_SM4_SWIZZLE_VEC4:
+                src_param->swizzle = swizzle_from_sm4((token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT);
+                break;
+
+            default:
+                FIXME("Unhandled swizzle type %#x.\n", swizzle_type);
+                break;
+        }
+    }
+
+    return true;
+}
+
+static bool shader_sm4_read_dst_param(struct vkd3d_sm4_data *priv, const DWORD **ptr, const DWORD *end,
+        enum vkd3d_data_type data_type, struct vkd3d_shader_dst_param *dst_param)
+{
+    enum vkd3d_shader_src_modifier modifier;
+    DWORD token;
+
+    if (*ptr >= end)
+    {
+        WARN("Invalid ptr %p >= end %p.\n", *ptr, end);
+        return false;
+    }
+    token = **ptr;
+
+    if (!shader_sm4_read_param(priv, ptr, end, data_type, &dst_param->reg, &modifier))
+    {
+        ERR("Failed to read parameter.\n");
+        return false;
+    }
+
+    if (modifier != VKD3DSPSM_NONE)
+    {
+        ERR("Invalid source modifier %#x on destination register.\n", modifier);
+        return false;
+    }
+
+    dst_param->write_mask = (token & VKD3D_SM4_WRITEMASK_MASK) >> VKD3D_SM4_WRITEMASK_SHIFT;
+    /* Scalar registers are declared with no write mask in shader bytecode. */
+    if (!dst_param->write_mask && shader_sm4_is_scalar_register(&dst_param->reg))
+        dst_param->write_mask = VKD3DSP_WRITEMASK_0;
+    dst_param->modifiers = 0;
+    dst_param->shift = 0;
+
+    return true;
+}
+
+static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_shader_instruction *ins)
+{
+    enum vkd3d_sm4_instruction_modifier modifier_type = modifier & VKD3D_SM4_MODIFIER_MASK;
+
+    switch (modifier_type)
+    {
+        case VKD3D_SM4_MODIFIER_AOFFIMMI:
+        {
+            static const DWORD recognized_bits = VKD3D_SM4_INSTRUCTION_MODIFIER
+                    | VKD3D_SM4_MODIFIER_MASK
+                    | VKD3D_SM4_AOFFIMMI_U_MASK
+                    | VKD3D_SM4_AOFFIMMI_V_MASK
+                    | VKD3D_SM4_AOFFIMMI_W_MASK;
+
+            /* Bit fields are used for sign extension. */
+            struct
+            {
+                int u : 4;
+                int v : 4;
+                int w : 4;
+            } aoffimmi;
+
+            if (modifier & ~recognized_bits)
+                FIXME("Unhandled instruction modifier %#x.\n", modifier);
+
+            aoffimmi.u = (modifier & VKD3D_SM4_AOFFIMMI_U_MASK) >> VKD3D_SM4_AOFFIMMI_U_SHIFT;
+            aoffimmi.v = (modifier & VKD3D_SM4_AOFFIMMI_V_MASK) >> VKD3D_SM4_AOFFIMMI_V_SHIFT;
+            aoffimmi.w = (modifier & VKD3D_SM4_AOFFIMMI_W_MASK) >> VKD3D_SM4_AOFFIMMI_W_SHIFT;
+            ins->texel_offset.u = aoffimmi.u;
+            ins->texel_offset.v = aoffimmi.v;
+            ins->texel_offset.w = aoffimmi.w;
+            break;
+        }
+
+        case VKD3D_SM5_MODIFIER_DATA_TYPE:
+        {
+            DWORD components = (modifier & VKD3D_SM5_MODIFIER_DATA_TYPE_MASK) >> VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT;
+            enum vkd3d_sm4_data_type data_type = components & 0xf;
+
+            if ((components & 0xfff0) != (components & 0xf) * 0x1110)
+                FIXME("Components (%#x) have different data types.\n", components);
+            if (data_type < ARRAY_SIZE(data_type_table))
+                ins->resource_data_type = data_type_table[data_type];
+            else
+            {
+                FIXME("Unhandled data type %#x.\n", data_type);
+                ins->resource_data_type = VKD3D_DATA_FLOAT;
+            }
+            break;
+        }
+
+        case VKD3D_SM5_MODIFIER_RESOURCE_TYPE:
+        {
+            enum vkd3d_sm4_resource_type resource_type
+                    = (modifier & VKD3D_SM5_MODIFIER_RESOURCE_TYPE_MASK) >> VKD3D_SM5_MODIFIER_RESOURCE_TYPE_SHIFT;
+
+            if (resource_type < ARRAY_SIZE(resource_type_table))
+                ins->resource_type = resource_type_table[resource_type];
+            else
+            {
+                FIXME("Unhandled resource type %#x.\n", resource_type);
+                ins->resource_type = VKD3D_SHADER_RESOURCE_NONE;
+            }
+            break;
+        }
+
+        default:
+            FIXME("Unhandled instruction modifier %#x.\n", modifier);
+    }
+}
+
+void shader_sm4_read_instruction(void *data, const DWORD **ptr, struct vkd3d_shader_instruction *ins)
+{
+    const struct vkd3d_sm4_opcode_info *opcode_info;
+    DWORD opcode_token, opcode, previous_token;
+    struct vkd3d_sm4_data *priv = data;
+    unsigned int i, len;
+    size_t remaining;
+    const DWORD *p;
+    DWORD precise;
+
+    list_move_head(&priv->src_free, &priv->src);
+
+    if (*ptr >= priv->end)
+    {
+        WARN("End of byte-code, failed to read opcode.\n");
+        goto fail;
+    }
+    remaining = priv->end - *ptr;
+
+    opcode_token = *(*ptr)++;
+    opcode = opcode_token & VKD3D_SM4_OPCODE_MASK;
+
+    len = ((opcode_token & VKD3D_SM4_INSTRUCTION_LENGTH_MASK) >> VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT);
+    if (!len)
+    {
+        if (remaining < 2)
+        {
+            WARN("End of byte-code, failed to read length token.\n");
+            goto fail;
+        }
+        len = **ptr;
+    }
+    if (!len || remaining < len)
+    {
+        WARN("Read invalid length %u (remaining %zu).\n", len, remaining);
+        goto fail;
+    }
+    --len;
+
+    if (!(opcode_info = get_opcode_info(opcode)))
+    {
+        FIXME("Unrecognized opcode %#x, opcode_token 0x%08x.\n", opcode, opcode_token);
+        ins->handler_idx = VKD3DSIH_INVALID;
+        *ptr += len;
+        return;
+    }
+
+    ins->handler_idx = opcode_info->handler_idx;
+    ins->flags = 0;
+    ins->coissue = false;
+    ins->predicate = NULL;
+    ins->dst_count = strlen(opcode_info->dst_info);
+    ins->dst = priv->dst_param;
+    ins->src_count = strlen(opcode_info->src_info);
+    ins->src = priv->src_param;
+    ins->resource_type = VKD3D_SHADER_RESOURCE_NONE;
+    ins->resource_data_type = VKD3D_DATA_FLOAT;
+    memset(&ins->texel_offset, 0, sizeof(ins->texel_offset));
+
+    p = *ptr;
+    *ptr += len;
+
+    if (opcode_info->read_opcode_func)
+    {
+        opcode_info->read_opcode_func(ins, opcode, opcode_token, p, len, priv);
+    }
+    else
+    {
+        enum vkd3d_shader_dst_modifier instruction_dst_modifier = VKD3DSPDM_NONE;
+
+        previous_token = opcode_token;
+        while (previous_token & VKD3D_SM4_INSTRUCTION_MODIFIER && p != *ptr)
+            shader_sm4_read_instruction_modifier(previous_token = *p++, ins);
+
+        ins->flags = (opcode_token & VKD3D_SM4_INSTRUCTION_FLAGS_MASK) >> VKD3D_SM4_INSTRUCTION_FLAGS_SHIFT;
+        if (ins->flags & VKD3D_SM4_INSTRUCTION_FLAG_SATURATE)
+        {
+            ins->flags &= ~VKD3D_SM4_INSTRUCTION_FLAG_SATURATE;
+            instruction_dst_modifier = VKD3DSPDM_SATURATE;
+        }
+        precise = (opcode_token & VKD3D_SM5_PRECISE_MASK) >> VKD3D_SM5_PRECISE_SHIFT;
+        ins->flags |= precise << VKD3DSI_PRECISE_SHIFT;
+
+        for (i = 0; i < ins->dst_count; ++i)
+        {
+            if (!(shader_sm4_read_dst_param(priv, &p, *ptr, map_data_type(opcode_info->dst_info[i]),
+                    &priv->dst_param[i])))
+            {
+                ins->handler_idx = VKD3DSIH_INVALID;
+                return;
+            }
+            priv->dst_param[i].modifiers |= instruction_dst_modifier;
+        }
+
+        for (i = 0; i < ins->src_count; ++i)
+        {
+            if (!(shader_sm4_read_src_param(priv, &p, *ptr, map_data_type(opcode_info->src_info[i]),
+                    &priv->src_param[i])))
+            {
+                ins->handler_idx = VKD3DSIH_INVALID;
+                return;
+            }
+        }
+    }
+
+    return;
+
+fail:
+    *ptr = priv->end;
+    ins->handler_idx = VKD3DSIH_INVALID;
+    return;
+}
+
+bool shader_sm4_is_end(void *data, const DWORD **ptr)
+{
+    struct vkd3d_sm4_data *priv = data;
+    return *ptr == priv->end;
+}
+
+#define MAKE_TAG(ch0, ch1, ch2, ch3) \
+    ((DWORD)(ch0) | ((DWORD)(ch1) << 8) | \
+    ((DWORD)(ch2) << 16) | ((DWORD)(ch3) << 24 ))
+#define TAG_DXBC MAKE_TAG('D', 'X', 'B', 'C')
+#define TAG_ISGN MAKE_TAG('I', 'S', 'G', 'N')
+#define TAG_ISG1 MAKE_TAG('I', 'S', 'G', '1')
+#define TAG_OSGN MAKE_TAG('O', 'S', 'G', 'N')
+#define TAG_OSG5 MAKE_TAG('O', 'S', 'G', '5')
+#define TAG_OSG1 MAKE_TAG('O', 'S', 'G', '1')
+#define TAG_PCSG MAKE_TAG('P', 'C', 'S', 'G')
+#define TAG_PSG1 MAKE_TAG('P', 'S', 'G', '1')
+#define TAG_SHDR MAKE_TAG('S', 'H', 'D', 'R')
+#define TAG_SHEX MAKE_TAG('S', 'H', 'E', 'X')
+#define TAG_AON9 MAKE_TAG('A', 'o', 'n', '9')
+#define TAG_RTS0 MAKE_TAG('R', 'T', 'S', '0')
+
+static bool require_space(size_t offset, size_t count, size_t size, size_t data_size)
+{
+    return !count || (data_size - offset) / count >= size;
+}
+
+static void read_dword(const char **ptr, DWORD *d)
+{
+    memcpy(d, *ptr, sizeof(*d));
+    *ptr += sizeof(*d);
+}
+
+static void read_float(const char **ptr, float *f)
+{
+    STATIC_ASSERT(sizeof(float) == sizeof(DWORD));
+    read_dword(ptr, (DWORD *)f);
+}
+
+static void skip_dword_unknown(const char **ptr, unsigned int count)
+{
+    unsigned int i;
+    DWORD d;
+
+    WARN("Skipping %u unknown DWORDs:\n", count);
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(ptr, &d);
+        WARN("\t0x%08x\n", d);
+    }
+}
+
+static const char *shader_get_string(const char *data, size_t data_size, DWORD offset)
+{
+    size_t len, max_len;
+
+    if (offset >= data_size)
+    {
+        WARN("Invalid offset %#x (data size %#lx).\n", offset, (long)data_size);
+        return NULL;
+    }
+
+    max_len = data_size - offset;
+    len = strnlen(data + offset, max_len);
+
+    if (len == max_len)
+        return NULL;
+
+    return data + offset;
+}
+
+static int parse_dxbc(const char *data, size_t data_size, struct vkd3d_shader_message_context *message_context,
+        int (*chunk_handler)(const char *data, DWORD data_size, DWORD tag, void *ctx), void *ctx)
+{
+    uint32_t checksum[4], calculated_checksum[4];
+    const char *ptr = data;
+    int ret = VKD3D_OK;
+    DWORD chunk_count;
+    DWORD total_size;
+    unsigned int i;
+    DWORD version;
+    DWORD tag;
+
+    if (data_size < VKD3D_DXBC_HEADER_SIZE)
+    {
+        WARN("Invalid data size %zu.\n", data_size);
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_SIZE,
+                "DXBC size %zu is smaller than the DXBC header size.", data_size);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &tag);
+    TRACE("tag: %#x.\n", tag);
+
+    if (tag != TAG_DXBC)
+    {
+        WARN("Wrong tag.\n");
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_MAGIC, "Invalid DXBC magic.");
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &checksum[0]);
+    read_dword(&ptr, &checksum[1]);
+    read_dword(&ptr, &checksum[2]);
+    read_dword(&ptr, &checksum[3]);
+    vkd3d_compute_dxbc_checksum(data, data_size, calculated_checksum);
+    if (memcmp(checksum, calculated_checksum, sizeof(checksum)))
+    {
+        WARN("Checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x} does not match "
+                "calculated checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x}.\n",
+                checksum[0], checksum[1], checksum[2], checksum[3],
+                calculated_checksum[0], calculated_checksum[1],
+                calculated_checksum[2], calculated_checksum[3]);
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_CHECKSUM, "Invalid DXBC checksum.");
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &version);
+    TRACE("version: %#x.\n", version);
+    if (version != 0x00000001)
+    {
+        WARN("Got unexpected DXBC version %#x.\n", version);
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_VERSION,
+                "DXBC version %#x is not supported.", version);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &total_size);
+    TRACE("total size: %#x\n", total_size);
+
+    read_dword(&ptr, &chunk_count);
+    TRACE("chunk count: %#x\n", chunk_count);
+
+    for (i = 0; i < chunk_count; ++i)
+    {
+        DWORD chunk_tag, chunk_size;
+        const char *chunk_ptr;
+        DWORD chunk_offset;
+
+        read_dword(&ptr, &chunk_offset);
+        TRACE("chunk %u at offset %#x\n", i, chunk_offset);
+
+        if (chunk_offset >= data_size || !require_space(chunk_offset, 2, sizeof(DWORD), data_size))
+        {
+            WARN("Invalid chunk offset %#x (data size %zu).\n", chunk_offset, data_size);
+            vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_OFFSET,
+                    "DXBC chunk %u has invalid offset %#x (data size %#zx).", i, chunk_offset, data_size);
+            return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+
+        chunk_ptr = data + chunk_offset;
+
+        read_dword(&chunk_ptr, &chunk_tag);
+        read_dword(&chunk_ptr, &chunk_size);
+
+        if (!require_space(chunk_ptr - data, 1, chunk_size, data_size))
+        {
+            WARN("Invalid chunk size %#x (data size %zu, chunk offset %#x).\n",
+                    chunk_size, data_size, chunk_offset);
+            vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_SIZE,
+                    "DXBC chunk %u has invalid size %#x (data size %#zx, chunk offset %#x).",
+                    i, chunk_offset, data_size, chunk_offset);
+            return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+
+        if ((ret = chunk_handler(chunk_ptr, chunk_size, chunk_tag, ctx)) < 0)
+            break;
+    }
+
+    return ret;
+}
+
+static int shader_parse_signature(DWORD tag, const char *data, DWORD data_size,
+        struct vkd3d_shader_signature *s)
+{
+    bool has_stream_index, has_min_precision;
+    struct vkd3d_shader_signature_element *e;
+    const char *ptr = data;
+    unsigned int i;
+    DWORD count;
+
+    if (!require_space(0, 2, sizeof(DWORD), data_size))
+    {
+        WARN("Invalid data size %#x.\n", data_size);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &count);
+    TRACE("%u elements.\n", count);
+
+    skip_dword_unknown(&ptr, 1); /* It seems to always be 0x00000008. */
+
+    if (!require_space(ptr - data, count, 6 * sizeof(DWORD), data_size))
+    {
+        WARN("Invalid count %#x (data size %#x).\n", count, data_size);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (!(e = vkd3d_calloc(count, sizeof(*e))))
+    {
+        ERR("Failed to allocate input signature memory.\n");
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+    }
+
+    has_min_precision = tag == TAG_OSG1 || tag == TAG_PSG1 || tag == TAG_ISG1;
+    has_stream_index = tag == TAG_OSG5 || has_min_precision;
+
+    for (i = 0; i < count; ++i)
+    {
+        DWORD name_offset, mask;
+
+        if (has_stream_index)
+            read_dword(&ptr, &e[i].stream_index);
+        else
+            e[i].stream_index = 0;
+
+        read_dword(&ptr, &name_offset);
+        if (!(e[i].semantic_name = shader_get_string(data, data_size, name_offset)))
+        {
+            WARN("Invalid name offset %#x (data size %#x).\n", name_offset, data_size);
+            vkd3d_free(e);
+            return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+        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_index);
+        read_dword(&ptr, &mask);
+        e[i].mask = mask & 0xff;
+        e[i].used_mask = (mask >> 8) & 0xff;
+        switch (tag)
+        {
+            case TAG_OSGN:
+            case TAG_OSG1:
+            case TAG_OSG5:
+            case TAG_PCSG:
+            case TAG_PSG1:
+                e[i].used_mask = e[i].mask & ~e[i].used_mask;
+                break;
+        }
+
+        if (has_min_precision)
+            read_dword(&ptr, &e[i].min_precision);
+        else
+            e[i].min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE;
+
+        TRACE("Stream: %u, semantic: %s, semantic idx: %u, sysval_semantic %#x, "
+                "type %u, register idx: %u, use_mask %#x, input_mask %#x, precision %u.\n",
+                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].used_mask, e[i].mask, e[i].min_precision);
+    }
+
+    s->elements = e;
+    s->element_count = count;
+
+    return VKD3D_OK;
+}
+
+static int isgn_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
+{
+    struct vkd3d_shader_signature *is = ctx;
+
+    if (tag != TAG_ISGN)
+        return VKD3D_OK;
+
+    if (is->elements)
+    {
+        FIXME("Multiple input signatures.\n");
+        vkd3d_shader_free_shader_signature(is);
+    }
+    return shader_parse_signature(tag, data, data_size, is);
+}
+
+int shader_parse_input_signature(const void *dxbc, size_t dxbc_length,
+        struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_signature *signature)
+{
+    int ret;
+
+    memset(signature, 0, sizeof(*signature));
+    if ((ret = parse_dxbc(dxbc, dxbc_length, message_context, isgn_handler, signature)) < 0)
+        ERR("Failed to parse input signature.\n");
+
+    return ret;
+}
+
+static int shdr_handler(const char *data, DWORD data_size, DWORD tag, void *context)
+{
+    struct vkd3d_shader_desc *desc = context;
+    int ret;
+
+    switch (tag)
+    {
+        case TAG_ISGN:
+        case TAG_ISG1:
+            if (desc->input_signature.elements)
+            {
+                FIXME("Multiple input signatures.\n");
+                break;
+            }
+            if ((ret = shader_parse_signature(tag, data, data_size, &desc->input_signature)) < 0)
+                return ret;
+            break;
+
+        case TAG_OSGN:
+        case TAG_OSG5:
+        case TAG_OSG1:
+            if (desc->output_signature.elements)
+            {
+                FIXME("Multiple output signatures.\n");
+                break;
+            }
+            if ((ret = shader_parse_signature(tag, data, data_size, &desc->output_signature)) < 0)
+                return ret;
+            break;
+
+        case TAG_PCSG:
+        case TAG_PSG1:
+            if (desc->patch_constant_signature.elements)
+            {
+                FIXME("Multiple patch constant signatures.\n");
+                break;
+            }
+            if ((ret = shader_parse_signature(tag, data, data_size, &desc->patch_constant_signature)) < 0)
+                return ret;
+            break;
+
+        case TAG_SHDR:
+        case TAG_SHEX:
+            if (desc->byte_code)
+                FIXME("Multiple shader code chunks.\n");
+            desc->byte_code = (const DWORD *)data;
+            desc->byte_code_size = data_size;
+            break;
+
+        case TAG_AON9:
+            TRACE("Skipping AON9 shader code chunk.\n");
+            break;
+
+        default:
+            TRACE("Skipping chunk %#x.\n", tag);
+            break;
+    }
+
+    return VKD3D_OK;
+}
+
+void free_shader_desc(struct vkd3d_shader_desc *desc)
+{
+    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);
+}
+
+int shader_extract_from_dxbc(const void *dxbc, size_t dxbc_length,
+        struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_desc *desc)
+{
+    int ret;
+
+    desc->byte_code = NULL;
+    desc->byte_code_size = 0;
+    memset(&desc->input_signature, 0, sizeof(desc->input_signature));
+    memset(&desc->output_signature, 0, sizeof(desc->output_signature));
+    memset(&desc->patch_constant_signature, 0, sizeof(desc->patch_constant_signature));
+
+    ret = parse_dxbc(dxbc, dxbc_length, message_context, shdr_handler, desc);
+    if (!desc->byte_code)
+        ret = VKD3D_ERROR_INVALID_ARGUMENT;
+
+    if (ret < 0)
+    {
+        WARN("Failed to parse shader, vkd3d result %d.\n", ret);
+        free_shader_desc(desc);
+    }
+
+    return ret;
+}
+
+/* root signatures */
+#define VKD3D_ROOT_SIGNATURE_1_0_ROOT_DESCRIPTOR_FLAGS VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE
+
+#define VKD3D_ROOT_SIGNATURE_1_0_DESCRIPTOR_RANGE_FLAGS \
+        (VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE)
+
+struct root_signature_parser_context
+{
+    const char *data;
+    unsigned int data_size;
+};
+
+static int shader_parse_descriptor_ranges(struct root_signature_parser_context *context,
+        unsigned int offset, unsigned int count, struct vkd3d_shader_descriptor_range *ranges)
+{
+    const char *ptr;
+    unsigned int i;
+
+    if (!require_space(offset, 5 * count, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(&ptr, &ranges[i].range_type);
+        read_dword(&ptr, &ranges[i].descriptor_count);
+        read_dword(&ptr, &ranges[i].base_shader_register);
+        read_dword(&ptr, &ranges[i].register_space);
+        read_dword(&ptr, &ranges[i].descriptor_table_offset);
+
+        TRACE("Type %#x, descriptor count %u, base shader register %u, "
+                "register space %u, offset %u.\n",
+                ranges[i].range_type, ranges[i].descriptor_count,
+                ranges[i].base_shader_register, ranges[i].register_space,
+                ranges[i].descriptor_table_offset);
+    }
+
+    return VKD3D_OK;
+}
+
+static void shader_validate_descriptor_range1(const struct vkd3d_shader_descriptor_range1 *range)
+{
+    unsigned int unknown_flags = range->flags & ~(VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_NONE
+            | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE
+            | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE
+            | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE
+            | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
+
+    if (unknown_flags)
+        FIXME("Unknown descriptor range flags %#x.\n", unknown_flags);
+}
+
+static int shader_parse_descriptor_ranges1(struct root_signature_parser_context *context,
+        unsigned int offset, unsigned int count, struct vkd3d_shader_descriptor_range1 *ranges)
+{
+    const char *ptr;
+    unsigned int i;
+
+    if (!require_space(offset, 6 * count, sizeof(uint32_t), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(&ptr, &ranges[i].range_type);
+        read_dword(&ptr, &ranges[i].descriptor_count);
+        read_dword(&ptr, &ranges[i].base_shader_register);
+        read_dword(&ptr, &ranges[i].register_space);
+        read_dword(&ptr, &ranges[i].flags);
+        read_dword(&ptr, &ranges[i].descriptor_table_offset);
+
+        TRACE("Type %#x, descriptor count %u, base shader register %u, "
+                "register space %u, flags %#x, offset %u.\n",
+                ranges[i].range_type, ranges[i].descriptor_count,
+                ranges[i].base_shader_register, ranges[i].register_space,
+                ranges[i].flags, ranges[i].descriptor_table_offset);
+
+        shader_validate_descriptor_range1(&ranges[i]);
+    }
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_descriptor_table(struct root_signature_parser_context *context,
+        unsigned int offset, struct vkd3d_shader_root_descriptor_table *table)
+{
+    struct vkd3d_shader_descriptor_range *ranges;
+    unsigned int count;
+    const char *ptr;
+
+    if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    read_dword(&ptr, &count);
+    read_dword(&ptr, &offset);
+
+    TRACE("Descriptor range count %u.\n", count);
+
+    table->descriptor_range_count = count;
+
+    if (!(ranges = vkd3d_calloc(count, sizeof(*ranges))))
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+    table->descriptor_ranges = ranges;
+    return shader_parse_descriptor_ranges(context, offset, count, ranges);
+}
+
+static int shader_parse_descriptor_table1(struct root_signature_parser_context *context,
+        unsigned int offset, struct vkd3d_shader_root_descriptor_table1 *table)
+{
+    struct vkd3d_shader_descriptor_range1 *ranges;
+    unsigned int count;
+    const char *ptr;
+
+    if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    read_dword(&ptr, &count);
+    read_dword(&ptr, &offset);
+
+    TRACE("Descriptor range count %u.\n", count);
+
+    table->descriptor_range_count = count;
+
+    if (!(ranges = vkd3d_calloc(count, sizeof(*ranges))))
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+    table->descriptor_ranges = ranges;
+    return shader_parse_descriptor_ranges1(context, offset, count, ranges);
+}
+
+static int shader_parse_root_constants(struct root_signature_parser_context *context,
+        unsigned int offset, struct vkd3d_shader_root_constants *constants)
+{
+    const char *ptr;
+
+    if (!require_space(offset, 3, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    read_dword(&ptr, &constants->shader_register);
+    read_dword(&ptr, &constants->register_space);
+    read_dword(&ptr, &constants->value_count);
+
+    TRACE("Shader register %u, register space %u, 32-bit value count %u.\n",
+            constants->shader_register, constants->register_space, constants->value_count);
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_root_descriptor(struct root_signature_parser_context *context,
+        unsigned int offset, struct vkd3d_shader_root_descriptor *descriptor)
+{
+    const char *ptr;
+
+    if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    read_dword(&ptr, &descriptor->shader_register);
+    read_dword(&ptr, &descriptor->register_space);
+
+    TRACE("Shader register %u, register space %u.\n",
+            descriptor->shader_register, descriptor->register_space);
+
+    return VKD3D_OK;
+}
+
+static void shader_validate_root_descriptor1(const struct vkd3d_shader_root_descriptor1 *descriptor)
+{
+    unsigned int unknown_flags = descriptor->flags & ~(VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_NONE
+            | VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE
+            | VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE
+            | VKD3D_SHADER_ROOT_DESCRIPTOR_FLAG_DATA_STATIC);
+
+    if (unknown_flags)
+        FIXME("Unknown root descriptor flags %#x.\n", unknown_flags);
+}
+
+static int shader_parse_root_descriptor1(struct root_signature_parser_context *context,
+        unsigned int offset, struct vkd3d_shader_root_descriptor1 *descriptor)
+{
+    const char *ptr;
+
+    if (!require_space(offset, 3, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    read_dword(&ptr, &descriptor->shader_register);
+    read_dword(&ptr, &descriptor->register_space);
+    read_dword(&ptr, &descriptor->flags);
+
+    TRACE("Shader register %u, register space %u, flags %#x.\n",
+            descriptor->shader_register, descriptor->register_space, descriptor->flags);
+
+    shader_validate_root_descriptor1(descriptor);
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_root_parameters(struct root_signature_parser_context *context,
+        unsigned int offset, unsigned int count, struct vkd3d_shader_root_parameter *parameters)
+{
+    const char *ptr;
+    unsigned int i;
+    int ret;
+
+    if (!require_space(offset, 3 * count, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(&ptr, &parameters[i].parameter_type);
+        read_dword(&ptr, &parameters[i].shader_visibility);
+        read_dword(&ptr, &offset);
+
+        TRACE("Type %#x, shader visibility %#x.\n",
+                parameters[i].parameter_type, parameters[i].shader_visibility);
+
+        switch (parameters[i].parameter_type)
+        {
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                ret = shader_parse_descriptor_table(context, offset, &parameters[i].u.descriptor_table);
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                ret = shader_parse_root_constants(context, offset, &parameters[i].u.constants);
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV:
+                ret = shader_parse_root_descriptor(context, offset, &parameters[i].u.descriptor);
+                break;
+            default:
+                FIXME("Unrecognized type %#x.\n", parameters[i].parameter_type);
+                return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+
+        if (ret < 0)
+            return ret;
+    }
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_root_parameters1(struct root_signature_parser_context *context,
+        DWORD offset, DWORD count, struct vkd3d_shader_root_parameter1 *parameters)
+{
+    const char *ptr;
+    unsigned int i;
+    int ret;
+
+    if (!require_space(offset, 3 * count, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(&ptr, &parameters[i].parameter_type);
+        read_dword(&ptr, &parameters[i].shader_visibility);
+        read_dword(&ptr, &offset);
+
+        TRACE("Type %#x, shader visibility %#x.\n",
+                parameters[i].parameter_type, parameters[i].shader_visibility);
+
+        switch (parameters[i].parameter_type)
+        {
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                ret = shader_parse_descriptor_table1(context, offset, &parameters[i].u.descriptor_table);
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                ret = shader_parse_root_constants(context, offset, &parameters[i].u.constants);
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV:
+                ret = shader_parse_root_descriptor1(context, offset, &parameters[i].u.descriptor);
+                break;
+            default:
+                FIXME("Unrecognized type %#x.\n", parameters[i].parameter_type);
+                return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+
+        if (ret < 0)
+            return ret;
+    }
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_static_samplers(struct root_signature_parser_context *context,
+        unsigned int offset, unsigned int count, struct vkd3d_shader_static_sampler_desc *sampler_descs)
+{
+    const char *ptr;
+    unsigned int i;
+
+    if (!require_space(offset, 13 * count, sizeof(DWORD), context->data_size))
+    {
+        WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    ptr = &context->data[offset];
+
+    for (i = 0; i < count; ++i)
+    {
+        read_dword(&ptr, &sampler_descs[i].filter);
+        read_dword(&ptr, &sampler_descs[i].address_u);
+        read_dword(&ptr, &sampler_descs[i].address_v);
+        read_dword(&ptr, &sampler_descs[i].address_w);
+        read_float(&ptr, &sampler_descs[i].mip_lod_bias);
+        read_dword(&ptr, &sampler_descs[i].max_anisotropy);
+        read_dword(&ptr, &sampler_descs[i].comparison_func);
+        read_dword(&ptr, &sampler_descs[i].border_colour);
+        read_float(&ptr, &sampler_descs[i].min_lod);
+        read_float(&ptr, &sampler_descs[i].max_lod);
+        read_dword(&ptr, &sampler_descs[i].shader_register);
+        read_dword(&ptr, &sampler_descs[i].register_space);
+        read_dword(&ptr, &sampler_descs[i].shader_visibility);
+    }
+
+    return VKD3D_OK;
+}
+
+static int shader_parse_root_signature(const char *data, unsigned int data_size,
+        struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    struct vkd3d_shader_root_signature_desc *v_1_0 = &desc->u.v_1_0;
+    struct root_signature_parser_context context;
+    unsigned int count, offset, version;
+    const char *ptr = data;
+    int ret;
+
+    context.data = data;
+    context.data_size = data_size;
+
+    if (!require_space(0, 6, sizeof(DWORD), data_size))
+    {
+        WARN("Invalid data size %#x.\n", data_size);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    read_dword(&ptr, &version);
+    TRACE("Version %#x.\n", version);
+    if (version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0 && version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        FIXME("Unknown version %#x.\n", version);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+    desc->version = version;
+
+    read_dword(&ptr, &count);
+    read_dword(&ptr, &offset);
+    TRACE("Parameter count %u, offset %u.\n", count, offset);
+
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+    {
+        v_1_0->parameter_count = count;
+        if (v_1_0->parameter_count)
+        {
+            struct vkd3d_shader_root_parameter *parameters;
+            if (!(parameters = vkd3d_calloc(v_1_0->parameter_count, sizeof(*parameters))))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+            v_1_0->parameters = parameters;
+            if ((ret = shader_parse_root_parameters(&context, offset, count, parameters)) < 0)
+                return ret;
+        }
+    }
+    else
+    {
+        struct vkd3d_shader_root_signature_desc1 *v_1_1 = &desc->u.v_1_1;
+
+        assert(version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1);
+
+        v_1_1->parameter_count = count;
+        if (v_1_1->parameter_count)
+        {
+            struct vkd3d_shader_root_parameter1 *parameters;
+            if (!(parameters = vkd3d_calloc(v_1_1->parameter_count, sizeof(*parameters))))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+            v_1_1->parameters = parameters;
+            if ((ret = shader_parse_root_parameters1(&context, offset, count, parameters)) < 0)
+                return ret;
+        }
+    }
+
+    read_dword(&ptr, &count);
+    read_dword(&ptr, &offset);
+    TRACE("Static sampler count %u, offset %u.\n", count, offset);
+
+    v_1_0->static_sampler_count = count;
+    if (v_1_0->static_sampler_count)
+    {
+        struct vkd3d_shader_static_sampler_desc *samplers;
+        if (!(samplers = vkd3d_calloc(v_1_0->static_sampler_count, sizeof(*samplers))))
+            return VKD3D_ERROR_OUT_OF_MEMORY;
+        v_1_0->static_samplers = samplers;
+        if ((ret = shader_parse_static_samplers(&context, offset, count, samplers)) < 0)
+            return ret;
+    }
+
+    read_dword(&ptr, &v_1_0->flags);
+    TRACE("Flags %#x.\n", v_1_0->flags);
+
+    return VKD3D_OK;
+}
+
+static int rts0_handler(const char *data, DWORD data_size, DWORD tag, void *context)
+{
+    struct vkd3d_shader_versioned_root_signature_desc *desc = context;
+
+    if (tag != TAG_RTS0)
+        return VKD3D_OK;
+
+    return shader_parse_root_signature(data, data_size, desc);
+}
+
+int vkd3d_shader_parse_root_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_versioned_root_signature_desc *root_signature, char **messages)
+{
+    struct vkd3d_shader_message_context message_context;
+    int ret;
+
+    TRACE("dxbc {%p, %zu}, root_signature %p, messages %p.\n", dxbc->code, dxbc->size, root_signature, messages);
+
+    memset(root_signature, 0, sizeof(*root_signature));
+    if (messages)
+        *messages = NULL;
+    if (!vkd3d_shader_message_context_init(&message_context, VKD3D_SHADER_LOG_INFO, NULL))
+        return VKD3D_ERROR;
+
+    ret = parse_dxbc(dxbc->code, dxbc->size, &message_context, rts0_handler, root_signature);
+    vkd3d_shader_message_context_trace_messages(&message_context);
+    if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&message_context)))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+
+    vkd3d_shader_message_context_cleanup(&message_context);
+    if (ret < 0)
+        vkd3d_shader_free_root_signature(root_signature);
+
+    return ret;
+}
+
+static unsigned int versioned_root_signature_get_parameter_count(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.parameter_count;
+    else
+        return desc->u.v_1_1.parameter_count;
+}
+
+static enum vkd3d_shader_root_parameter_type versioned_root_signature_get_parameter_type(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc, unsigned int i)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.parameters[i].parameter_type;
+    else
+        return desc->u.v_1_1.parameters[i].parameter_type;
+}
+
+static enum vkd3d_shader_visibility versioned_root_signature_get_parameter_shader_visibility(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc, unsigned int i)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.parameters[i].shader_visibility;
+    else
+        return desc->u.v_1_1.parameters[i].shader_visibility;
+}
+
+static const struct vkd3d_shader_root_constants *versioned_root_signature_get_root_constants(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc, unsigned int i)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return &desc->u.v_1_0.parameters[i].u.constants;
+    else
+        return &desc->u.v_1_1.parameters[i].u.constants;
+}
+
+static unsigned int versioned_root_signature_get_static_sampler_count(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.static_sampler_count;
+    else
+        return desc->u.v_1_1.static_sampler_count;
+}
+
+static const struct vkd3d_shader_static_sampler_desc *versioned_root_signature_get_static_samplers(
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.static_samplers;
+    else
+        return desc->u.v_1_1.static_samplers;
+}
+
+static unsigned int versioned_root_signature_get_flags(const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+        return desc->u.v_1_0.flags;
+    else
+        return desc->u.v_1_1.flags;
+}
+
+struct root_signature_writer_context
+{
+    struct vkd3d_shader_message_context message_context;
+
+    DWORD *data;
+    size_t position;
+    size_t capacity;
+
+    size_t total_size_position;
+    size_t chunk_position;
+};
+
+static bool write_dwords(struct root_signature_writer_context *context,
+        unsigned int count, DWORD d)
+{
+    unsigned int i;
+
+    if (!vkd3d_array_reserve((void **)&context->data, &context->capacity,
+            context->position + count, sizeof(*context->data)))
+        return false;
+    for (i = 0; i < count; ++i)
+        context->data[context->position++] = d;
+    return true;
+}
+
+static bool write_dword(struct root_signature_writer_context *context, DWORD d)
+{
+    return write_dwords(context, 1, d);
+}
+
+static bool write_float(struct root_signature_writer_context *context, float f)
+{
+    union
+    {
+        float f;
+        DWORD d;
+    } u;
+    u.f = f;
+    return write_dword(context, u.d);
+}
+
+static size_t get_chunk_offset(struct root_signature_writer_context *context)
+{
+    return (context->position - context->chunk_position) * sizeof(DWORD);
+}
+
+static int shader_write_root_signature_header(struct root_signature_writer_context *context)
+{
+    if (!write_dword(context, TAG_DXBC))
+        goto fail;
+
+    /* The checksum is computed when all data is generated. */
+    if (!write_dwords(context, 4, 0x00000000))
+        goto fail;
+
+    if (!write_dword(context, 0x00000001))
+        goto fail;
+
+    context->total_size_position = context->position;
+    if (!write_dword(context, 0xffffffff)) /* total size */
+        goto fail;
+
+    if (!write_dword(context, 1)) /* chunk count */
+        goto fail;
+
+    /* chunk offset */
+    if (!write_dword(context, (context->position + 1) * sizeof(DWORD)))
+        goto fail;
+
+    if (!write_dword(context, TAG_RTS0))
+        goto fail;
+    if (!write_dword(context, 0xffffffff)) /* chunk size */
+        goto fail;
+    context->chunk_position = context->position;
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature header.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_descriptor_ranges(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor_table *table)
+{
+    const struct vkd3d_shader_descriptor_range *ranges = table->descriptor_ranges;
+    unsigned int i;
+
+    for (i = 0; i < table->descriptor_range_count; ++i)
+    {
+        if (!write_dword(context, ranges[i].range_type))
+            goto fail;
+        if (!write_dword(context, ranges[i].descriptor_count))
+            goto fail;
+        if (!write_dword(context, ranges[i].base_shader_register))
+            goto fail;
+        if (!write_dword(context, ranges[i].register_space))
+            goto fail;
+        if (!write_dword(context, ranges[i].descriptor_table_offset))
+            goto fail;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature descriptor ranges.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_descriptor_ranges1(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor_table1 *table)
+{
+    const struct vkd3d_shader_descriptor_range1 *ranges = table->descriptor_ranges;
+    unsigned int i;
+
+    for (i = 0; i < table->descriptor_range_count; ++i)
+    {
+        if (!write_dword(context, ranges[i].range_type))
+            goto fail;
+        if (!write_dword(context, ranges[i].descriptor_count))
+            goto fail;
+        if (!write_dword(context, ranges[i].base_shader_register))
+            goto fail;
+        if (!write_dword(context, ranges[i].register_space))
+            goto fail;
+        if (!write_dword(context, ranges[i].flags))
+            goto fail;
+        if (!write_dword(context, ranges[i].descriptor_table_offset))
+            goto fail;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature descriptor ranges.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_descriptor_table(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor_table *table)
+{
+    if (!write_dword(context, table->descriptor_range_count))
+        goto fail;
+    if (!write_dword(context, get_chunk_offset(context) + sizeof(DWORD))) /* offset */
+        goto fail;
+
+    return shader_write_descriptor_ranges(context, table);
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root descriptor table.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_descriptor_table1(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor_table1 *table)
+{
+    if (!write_dword(context, table->descriptor_range_count))
+        goto fail;
+    if (!write_dword(context, get_chunk_offset(context) + sizeof(DWORD))) /* offset */
+        goto fail;
+
+    return shader_write_descriptor_ranges1(context, table);
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root descriptor table.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_root_constants(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_constants *constants)
+{
+    if (!write_dword(context, constants->shader_register))
+        goto fail;
+    if (!write_dword(context, constants->register_space))
+        goto fail;
+    if (!write_dword(context, constants->value_count))
+        goto fail;
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root constants.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_root_descriptor(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor *descriptor)
+{
+    if (!write_dword(context, descriptor->shader_register))
+        goto fail;
+    if (!write_dword(context, descriptor->register_space))
+        goto fail;
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root descriptor.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_root_descriptor1(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_root_descriptor1 *descriptor)
+{
+    if (!write_dword(context, descriptor->shader_register))
+        goto fail;
+    if (!write_dword(context, descriptor->register_space))
+        goto fail;
+    if (!write_dword(context, descriptor->flags))
+        goto fail;
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root descriptor.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_root_parameters(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    unsigned int parameter_count = versioned_root_signature_get_parameter_count(desc);
+    size_t parameters_position;
+    unsigned int i;
+    int ret;
+
+    parameters_position = context->position;
+    for (i = 0; i < parameter_count; ++i)
+    {
+        if (!write_dword(context, versioned_root_signature_get_parameter_type(desc, i)))
+            goto fail;
+        if (!write_dword(context, versioned_root_signature_get_parameter_shader_visibility(desc, i)))
+            goto fail;
+        if (!write_dword(context, 0xffffffff)) /* offset */
+            goto fail;
+    }
+
+    for (i = 0; i < parameter_count; ++i)
+    {
+        context->data[parameters_position + 3 * i + 2] = get_chunk_offset(context); /* offset */
+
+        switch (versioned_root_signature_get_parameter_type(desc, i))
+        {
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+                    ret = shader_write_descriptor_table(context, &desc->u.v_1_0.parameters[i].u.descriptor_table);
+                else
+                    ret = shader_write_descriptor_table1(context, &desc->u.v_1_1.parameters[i].u.descriptor_table);
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                ret = shader_write_root_constants(context, versioned_root_signature_get_root_constants(desc, i));
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV:
+                if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+                    ret = shader_write_root_descriptor(context, &desc->u.v_1_0.parameters[i].u.descriptor);
+                else
+                    ret = shader_write_root_descriptor1(context, &desc->u.v_1_1.parameters[i].u.descriptor);
+                break;
+            default:
+                FIXME("Unrecognized type %#x.\n", versioned_root_signature_get_parameter_type(desc, i));
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_INVALID_ROOT_PARAMETER_TYPE,
+                        "Invalid/unrecognised root signature root parameter type %#x.",
+                        versioned_root_signature_get_parameter_type(desc, i));
+                return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+
+        if (ret < 0)
+            return ret;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature root parameters.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_static_samplers(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    const struct vkd3d_shader_static_sampler_desc *samplers = versioned_root_signature_get_static_samplers(desc);
+    unsigned int i;
+
+    for (i = 0; i < versioned_root_signature_get_static_sampler_count(desc); ++i)
+    {
+        if (!write_dword(context, samplers[i].filter))
+            goto fail;
+        if (!write_dword(context, samplers[i].address_u))
+            goto fail;
+        if (!write_dword(context, samplers[i].address_v))
+            goto fail;
+        if (!write_dword(context, samplers[i].address_w))
+            goto fail;
+        if (!write_float(context, samplers[i].mip_lod_bias))
+            goto fail;
+        if (!write_dword(context, samplers[i].max_anisotropy))
+            goto fail;
+        if (!write_dword(context, samplers[i].comparison_func))
+            goto fail;
+        if (!write_dword(context, samplers[i].border_colour))
+            goto fail;
+        if (!write_float(context, samplers[i].min_lod))
+            goto fail;
+        if (!write_float(context, samplers[i].max_lod))
+            goto fail;
+        if (!write_dword(context, samplers[i].shader_register))
+            goto fail;
+        if (!write_dword(context, samplers[i].register_space))
+            goto fail;
+        if (!write_dword(context, samplers[i].shader_visibility))
+            goto fail;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature static samplers.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int shader_write_root_signature(struct root_signature_writer_context *context,
+        const struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    size_t samplers_offset_position;
+    int ret;
+
+    if (!write_dword(context, desc->version))
+        goto fail;
+
+    if (!write_dword(context, versioned_root_signature_get_parameter_count(desc)))
+        goto fail;
+    if (!write_dword(context, get_chunk_offset(context) + 4 * sizeof(DWORD))) /* offset */
+        goto fail;
+
+    if (!write_dword(context, versioned_root_signature_get_static_sampler_count(desc)))
+        goto fail;
+    samplers_offset_position = context->position;
+    if (!write_dword(context, 0xffffffff)) /* offset */
+        goto fail;
+
+    if (!write_dword(context, versioned_root_signature_get_flags(desc)))
+        goto fail;
+
+    if ((ret = shader_write_root_parameters(context, desc)) < 0)
+        return ret;
+
+    context->data[samplers_offset_position] = get_chunk_offset(context);
+    return shader_write_static_samplers(context, desc);
+
+fail:
+    vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY,
+            "Out of memory while writing root signature.");
+    return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static int validate_descriptor_table_v_1_0(const struct vkd3d_shader_root_descriptor_table *descriptor_table,
+        struct vkd3d_shader_message_context *message_context)
+{
+    bool have_srv_uav_cbv = false;
+    bool have_sampler = false;
+    unsigned int i;
+
+    for (i = 0; i < descriptor_table->descriptor_range_count; ++i)
+    {
+        const struct vkd3d_shader_descriptor_range *r = &descriptor_table->descriptor_ranges[i];
+
+        if (r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV
+                || r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV
+                || r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV)
+        {
+            have_srv_uav_cbv = true;
+        }
+        else if (r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
+        {
+            have_sampler = true;
+        }
+        else
+        {
+            WARN("Invalid descriptor range type %#x.\n", r->range_type);
+            vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_RS_INVALID_DESCRIPTOR_RANGE_TYPE,
+                    "Invalid root signature descriptor range type %#x.", r->range_type);
+            return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    if (have_srv_uav_cbv && have_sampler)
+    {
+        WARN("Samplers cannot be mixed with CBVs/SRVs/UAVs in descriptor tables.\n");
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_RS_MIXED_DESCRIPTOR_RANGE_TYPES,
+                "Encountered both CBV/SRV/UAV and sampler descriptor ranges in the same root descriptor table.");
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    return VKD3D_OK;
+}
+
+static int validate_descriptor_table_v_1_1(const struct vkd3d_shader_root_descriptor_table1 *descriptor_table,
+        struct vkd3d_shader_message_context *message_context)
+{
+    bool have_srv_uav_cbv = false;
+    bool have_sampler = false;
+    unsigned int i;
+
+    for (i = 0; i < descriptor_table->descriptor_range_count; ++i)
+    {
+        const struct vkd3d_shader_descriptor_range1 *r = &descriptor_table->descriptor_ranges[i];
+
+        if (r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV
+                || r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV
+                || r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV)
+        {
+            have_srv_uav_cbv = true;
+        }
+        else if (r->range_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
+        {
+            have_sampler = true;
+        }
+        else
+        {
+            WARN("Invalid descriptor range type %#x.\n", r->range_type);
+            vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_RS_INVALID_DESCRIPTOR_RANGE_TYPE,
+                    "Invalid root signature descriptor range type %#x.", r->range_type);
+            return VKD3D_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    if (have_srv_uav_cbv && have_sampler)
+    {
+        WARN("Samplers cannot be mixed with CBVs/SRVs/UAVs in descriptor tables.\n");
+        vkd3d_shader_error(message_context, VKD3D_SHADER_ERROR_RS_MIXED_DESCRIPTOR_RANGE_TYPES,
+                "Encountered both CBV/SRV/UAV and sampler descriptor ranges in the same root descriptor table.");
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    return VKD3D_OK;
+}
+
+static int validate_root_signature_desc(const struct vkd3d_shader_versioned_root_signature_desc *desc,
+        struct vkd3d_shader_message_context *message_context)
+{
+    int ret = VKD3D_OK;
+    unsigned int i;
+
+    for (i = 0; i < versioned_root_signature_get_parameter_count(desc); ++i)
+    {
+        enum vkd3d_shader_root_parameter_type type;
+
+        type = versioned_root_signature_get_parameter_type(desc, i);
+        if (type == VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+        {
+            if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+                ret = validate_descriptor_table_v_1_0(&desc->u.v_1_0.parameters[i].u.descriptor_table, message_context);
+            else
+                ret = validate_descriptor_table_v_1_1(&desc->u.v_1_1.parameters[i].u.descriptor_table, message_context);
+        }
+
+        if (ret < 0)
+            break;
+    }
+
+    return ret;
+}
+
+int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_root_signature_desc *root_signature,
+        struct vkd3d_shader_code *dxbc, char **messages)
+{
+    struct root_signature_writer_context context;
+    size_t total_size, chunk_size;
+    uint32_t checksum[4];
+    int ret;
+
+    TRACE("root_signature %p, dxbc %p, messages %p.\n", root_signature, dxbc, messages);
+
+    if (messages)
+        *messages = NULL;
+
+    memset(&context, 0, sizeof(context));
+    if (!vkd3d_shader_message_context_init(&context.message_context, VKD3D_SHADER_LOG_INFO, NULL))
+        return VKD3D_ERROR;
+
+    if (root_signature->version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0
+            && root_signature->version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        ret = VKD3D_ERROR_INVALID_ARGUMENT;
+        WARN("Root signature version %#x not supported.\n", root_signature->version);
+        vkd3d_shader_error(&context.message_context, VKD3D_SHADER_ERROR_RS_INVALID_VERSION,
+                "Root signature version %#x is not supported.", root_signature->version);
+        goto done;
+    }
+
+    if ((ret = validate_root_signature_desc(root_signature, &context.message_context)) < 0)
+        goto done;
+
+    memset(dxbc, 0, sizeof(*dxbc));
+    if ((ret = shader_write_root_signature_header(&context)) < 0)
+    {
+        vkd3d_free(context.data);
+        goto done;
+    }
+
+    if ((ret = shader_write_root_signature(&context, root_signature)) < 0)
+    {
+        vkd3d_free(context.data);
+        goto done;
+    }
+
+    total_size = context.position * sizeof(DWORD);
+    chunk_size = get_chunk_offset(&context);
+    context.data[context.total_size_position] = total_size;
+    context.data[context.chunk_position - 1] = chunk_size;
+
+    dxbc->code = context.data;
+    dxbc->size = total_size;
+
+    vkd3d_compute_dxbc_checksum(dxbc->code, dxbc->size, checksum);
+    memcpy((uint32_t *)dxbc->code + 1, checksum, sizeof(checksum));
+
+    ret = VKD3D_OK;
+
+done:
+    vkd3d_shader_message_context_trace_messages(&context.message_context);
+    if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&context.message_context)))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+    vkd3d_shader_message_context_cleanup(&context.message_context);
+    return ret;
+}
+
+static void free_descriptor_ranges(const struct vkd3d_shader_root_parameter *parameters, unsigned int count)
+{
+    unsigned int i;
+
+    if (!parameters)
+        return;
+
+    for (i = 0; i < count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter *p = &parameters[i];
+
+        if (p->parameter_type == VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            vkd3d_free((void *)p->u.descriptor_table.descriptor_ranges);
+    }
+}
+
+static int convert_root_parameters_to_v_1_0(struct vkd3d_shader_root_parameter *dst,
+        const struct vkd3d_shader_root_parameter1 *src, unsigned int count)
+{
+    const struct vkd3d_shader_descriptor_range1 *ranges1;
+    struct vkd3d_shader_descriptor_range *ranges;
+    unsigned int i, j;
+    int ret;
+
+    for (i = 0; i < count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter1 *p1 = &src[i];
+        struct vkd3d_shader_root_parameter *p = &dst[i];
+
+        p->parameter_type = p1->parameter_type;
+        switch (p->parameter_type)
+        {
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                ranges = NULL;
+                if ((p->u.descriptor_table.descriptor_range_count = p1->u.descriptor_table.descriptor_range_count))
+                {
+                    if (!(ranges = vkd3d_calloc(p->u.descriptor_table.descriptor_range_count, sizeof(*ranges))))
+                    {
+                        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+                        goto fail;
+                    }
+                }
+                p->u.descriptor_table.descriptor_ranges = ranges;
+                ranges1 = p1->u.descriptor_table.descriptor_ranges;
+                for (j = 0; j < p->u.descriptor_table.descriptor_range_count; ++j)
+                {
+                    ranges[j].range_type = ranges1[j].range_type;
+                    ranges[j].descriptor_count = ranges1[j].descriptor_count;
+                    ranges[j].base_shader_register = ranges1[j].base_shader_register;
+                    ranges[j].register_space = ranges1[j].register_space;
+                    ranges[j].descriptor_table_offset = ranges1[j].descriptor_table_offset;
+                }
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                p->u.constants = p1->u.constants;
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV:
+                p->u.descriptor.shader_register = p1->u.descriptor.shader_register;
+                p->u.descriptor.register_space = p1->u.descriptor.register_space;
+                break;
+            default:
+                WARN("Invalid root parameter type %#x.\n", p->parameter_type);
+                ret = VKD3D_ERROR_INVALID_ARGUMENT;
+                goto fail;
+
+        }
+        p->shader_visibility = p1->shader_visibility;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    free_descriptor_ranges(dst, i);
+    return ret;
+}
+
+static int convert_root_signature_to_v1_0(struct vkd3d_shader_versioned_root_signature_desc *dst,
+        const struct vkd3d_shader_versioned_root_signature_desc *src)
+{
+    const struct vkd3d_shader_root_signature_desc1 *src_desc = &src->u.v_1_1;
+    struct vkd3d_shader_root_signature_desc *dst_desc = &dst->u.v_1_0;
+    struct vkd3d_shader_static_sampler_desc *samplers = NULL;
+    struct vkd3d_shader_root_parameter *parameters = NULL;
+    int ret;
+
+    if ((dst_desc->parameter_count = src_desc->parameter_count))
+    {
+        if (!(parameters = vkd3d_calloc(dst_desc->parameter_count, sizeof(*parameters))))
+        {
+            ret = VKD3D_ERROR_OUT_OF_MEMORY;
+            goto fail;
+        }
+        if ((ret = convert_root_parameters_to_v_1_0(parameters, src_desc->parameters, src_desc->parameter_count)) < 0)
+            goto fail;
+    }
+    dst_desc->parameters = parameters;
+    if ((dst_desc->static_sampler_count = src_desc->static_sampler_count))
+    {
+        if (!(samplers = vkd3d_calloc(dst_desc->static_sampler_count, sizeof(*samplers))))
+        {
+            ret = VKD3D_ERROR_OUT_OF_MEMORY;
+            goto fail;
+        }
+        memcpy(samplers, src_desc->static_samplers, src_desc->static_sampler_count * sizeof(*samplers));
+    }
+    dst_desc->static_samplers = samplers;
+    dst_desc->flags = src_desc->flags;
+
+    return VKD3D_OK;
+
+fail:
+    free_descriptor_ranges(parameters, dst_desc->parameter_count);
+    vkd3d_free(parameters);
+    vkd3d_free(samplers);
+    return ret;
+}
+
+static void free_descriptor_ranges1(const struct vkd3d_shader_root_parameter1 *parameters, unsigned int count)
+{
+    unsigned int i;
+
+    if (!parameters)
+        return;
+
+    for (i = 0; i < count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter1 *p = &parameters[i];
+
+        if (p->parameter_type == VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            vkd3d_free((void *)p->u.descriptor_table.descriptor_ranges);
+    }
+}
+
+static int convert_root_parameters_to_v_1_1(struct vkd3d_shader_root_parameter1 *dst,
+        const struct vkd3d_shader_root_parameter *src, unsigned int count)
+{
+    const struct vkd3d_shader_descriptor_range *ranges;
+    struct vkd3d_shader_descriptor_range1 *ranges1;
+    unsigned int i, j;
+    int ret;
+
+    for (i = 0; i < count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter *p = &src[i];
+        struct vkd3d_shader_root_parameter1 *p1 = &dst[i];
+
+        p1->parameter_type = p->parameter_type;
+        switch (p1->parameter_type)
+        {
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                ranges1 = NULL;
+                if ((p1->u.descriptor_table.descriptor_range_count = p->u.descriptor_table.descriptor_range_count))
+                {
+                    if (!(ranges1 = vkd3d_calloc(p1->u.descriptor_table.descriptor_range_count, sizeof(*ranges1))))
+                    {
+                        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+                        goto fail;
+                    }
+                }
+                p1->u.descriptor_table.descriptor_ranges = ranges1;
+                ranges = p->u.descriptor_table.descriptor_ranges;
+                for (j = 0; j < p1->u.descriptor_table.descriptor_range_count; ++j)
+                {
+                    ranges1[j].range_type = ranges[j].range_type;
+                    ranges1[j].descriptor_count = ranges[j].descriptor_count;
+                    ranges1[j].base_shader_register = ranges[j].base_shader_register;
+                    ranges1[j].register_space = ranges[j].register_space;
+                    ranges1[j].flags = VKD3D_ROOT_SIGNATURE_1_0_DESCRIPTOR_RANGE_FLAGS;
+                    ranges1[j].descriptor_table_offset = ranges[j].descriptor_table_offset;
+                }
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                p1->u.constants = p->u.constants;
+                break;
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_CBV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_SRV:
+            case VKD3D_SHADER_ROOT_PARAMETER_TYPE_UAV:
+                p1->u.descriptor.shader_register = p->u.descriptor.shader_register;
+                p1->u.descriptor.register_space = p->u.descriptor.register_space;
+                p1->u.descriptor.flags = VKD3D_ROOT_SIGNATURE_1_0_ROOT_DESCRIPTOR_FLAGS;
+                break;
+            default:
+                WARN("Invalid root parameter type %#x.\n", p1->parameter_type);
+                ret = VKD3D_ERROR_INVALID_ARGUMENT;
+                goto fail;
+
+        }
+        p1->shader_visibility = p->shader_visibility;
+    }
+
+    return VKD3D_OK;
+
+fail:
+    free_descriptor_ranges1(dst, i);
+    return ret;
+}
+
+static int convert_root_signature_to_v1_1(struct vkd3d_shader_versioned_root_signature_desc *dst,
+        const struct vkd3d_shader_versioned_root_signature_desc *src)
+{
+    const struct vkd3d_shader_root_signature_desc *src_desc = &src->u.v_1_0;
+    struct vkd3d_shader_root_signature_desc1 *dst_desc = &dst->u.v_1_1;
+    struct vkd3d_shader_static_sampler_desc *samplers = NULL;
+    struct vkd3d_shader_root_parameter1 *parameters = NULL;
+    int ret;
+
+    if ((dst_desc->parameter_count = src_desc->parameter_count))
+    {
+        if (!(parameters = vkd3d_calloc(dst_desc->parameter_count, sizeof(*parameters))))
+        {
+            ret = VKD3D_ERROR_OUT_OF_MEMORY;
+            goto fail;
+        }
+        if ((ret = convert_root_parameters_to_v_1_1(parameters, src_desc->parameters, src_desc->parameter_count)) < 0)
+            goto fail;
+    }
+    dst_desc->parameters = parameters;
+    if ((dst_desc->static_sampler_count = src_desc->static_sampler_count))
+    {
+        if (!(samplers = vkd3d_calloc(dst_desc->static_sampler_count, sizeof(*samplers))))
+        {
+            ret = VKD3D_ERROR_OUT_OF_MEMORY;
+            goto fail;
+        }
+        memcpy(samplers, src_desc->static_samplers, src_desc->static_sampler_count * sizeof(*samplers));
+    }
+    dst_desc->static_samplers = samplers;
+    dst_desc->flags = src_desc->flags;
+
+    return VKD3D_OK;
+
+fail:
+    free_descriptor_ranges1(parameters, dst_desc->parameter_count);
+    vkd3d_free(parameters);
+    vkd3d_free(samplers);
+    return ret;
+}
+
+int vkd3d_shader_convert_root_signature(struct vkd3d_shader_versioned_root_signature_desc *dst,
+        enum vkd3d_shader_root_signature_version version, const struct vkd3d_shader_versioned_root_signature_desc *src)
+{
+    int ret;
+
+    TRACE("dst %p, version %#x, src %p.\n", dst, version, src);
+
+    if (src->version == version)
+    {
+        WARN("Nothing to convert.\n");
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0 && version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        WARN("Root signature version %#x not supported.\n", version);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (src->version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0
+            && src->version != VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        WARN("Root signature version %#x not supported.\n", src->version);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    memset(dst, 0, sizeof(*dst));
+    dst->version = version;
+
+    if (version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+    {
+        ret = convert_root_signature_to_v1_0(dst, src);
+    }
+    else
+    {
+        assert(version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1);
+        ret = convert_root_signature_to_v1_1(dst, src);
+    }
+
+    return ret;
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/libvkd3d-shader.pc.in b/dlls/vkd3d/libs/vkd3d-shader/libvkd3d-shader.pc.in
new file mode 100644
index 00000000000..b93e6ed9c6d
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/libvkd3d-shader.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: vkd3d-shader
+Description: The vkd3d Shader Translation Library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}/vkd3d
+Libs: -L${libdir} -lvkd3d-shader
diff --git a/dlls/vkd3d/libs/vkd3d-shader/spirv.c b/dlls/vkd3d/libs/vkd3d-shader/spirv.c
new file mode 100644
index 00000000000..44fe35c72c5
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/spirv.c
@@ -0,0 +1,9281 @@
+/*
+ * Copyright 2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_shader_private.h"
+#include "rbtree.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef HAVE_SPIRV_UNIFIED1_SPIRV_H
+# include "spirv/unified1/spirv.h"
+#else
+# include "vulkan/spirv.h"
+#endif  /* HAVE_SPIRV_UNIFIED1_SPIRV_H */
+#ifdef HAVE_SPIRV_UNIFIED1_GLSL_STD_450_H
+# include "spirv/unified1/GLSL.std.450.h"
+#else
+# include "vulkan/GLSL.std.450.h"
+#endif  /* HAVE_SPIRV_UNIFIED1_GLSL_STD_450_H */
+
+#ifdef HAVE_SPIRV_TOOLS
+# include "spirv-tools/libspirv.h"
+
+static spv_target_env spv_target_env_from_vkd3d(enum vkd3d_shader_spirv_environment environment)
+{
+    switch (environment)
+    {
+        case VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5:
+            return SPV_ENV_OPENGL_4_5;
+        case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
+            return SPV_ENV_VULKAN_1_0;
+        default:
+            ERR("Invalid environment %#x.\n", environment);
+            return SPV_ENV_VULKAN_1_0;
+    }
+}
+
+static uint32_t get_binary_to_text_options(enum vkd3d_shader_compile_option_formatting_flags formatting)
+{
+    uint32_t out = 0;
+    unsigned int i;
+
+    static const struct
+    {
+        enum vkd3d_shader_compile_option_formatting_flags vkd3d;
+        uint32_t spv;
+        bool invert;
+    }
+    valuemap[] =
+    {
+        {VKD3D_SHADER_COMPILE_OPTION_FORMATTING_COLOUR,     SPV_BINARY_TO_TEXT_OPTION_COLOR           },
+        {VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT,     SPV_BINARY_TO_TEXT_OPTION_INDENT          },
+        {VKD3D_SHADER_COMPILE_OPTION_FORMATTING_OFFSETS,    SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET},
+        {VKD3D_SHADER_COMPILE_OPTION_FORMATTING_HEADER,     SPV_BINARY_TO_TEXT_OPTION_NO_HEADER,        true},
+        {VKD3D_SHADER_COMPILE_OPTION_FORMATTING_RAW_IDS,    SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES,   true},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(valuemap); ++i)
+    {
+        if (valuemap[i].invert == !(formatting & valuemap[i].vkd3d))
+            out |= valuemap[i].spv;
+    }
+
+    return out;
+}
+
+static enum vkd3d_result vkd3d_spirv_binary_to_text(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment, uint32_t options, struct vkd3d_shader_code *out)
+{
+    spv_diagnostic diagnostic = NULL;
+    spv_text text = NULL;
+    spv_context context;
+    spv_result_t spvret;
+    enum vkd3d_result result = VKD3D_OK;
+
+    context = spvContextCreate(spv_target_env_from_vkd3d(environment));
+
+    if (!(spvret = spvBinaryToText(context, spirv->code, spirv->size / sizeof(uint32_t),
+            options, &text, &diagnostic)))
+    {
+        void *code = vkd3d_malloc(text->length);
+        if (code)
+        {
+            memcpy(code, text->str, text->length);
+            out->size = text->length;
+            out->code = code;
+        }
+        else
+            result = VKD3D_ERROR_OUT_OF_MEMORY;
+    }
+    else
+    {
+        FIXME("Failed to convert SPIR-V binary to text, ret %d.\n", spvret);
+        FIXME("Diagnostic message: %s.\n", debugstr_a(diagnostic->error));
+        result = VKD3D_ERROR;
+    }
+
+    spvTextDestroy(text);
+    spvDiagnosticDestroy(diagnostic);
+    spvContextDestroy(context);
+
+    return result;
+}
+
+static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment)
+{
+    const static uint32_t options
+        = SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT;
+    struct vkd3d_shader_code text;
+
+    if (!vkd3d_spirv_binary_to_text(spirv, environment, options, &text))
+    {
+        const char *str, *current = text.code;
+        while ((str = strchr(current, '\n')))
+        {
+            TRACE("%.*s\n", (int)(str - current), current);
+            current = str + 1;
+        }
+
+        vkd3d_shader_free_shader_code(&text);
+    }
+}
+
+static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment)
+{
+    spv_diagnostic diagnostic = NULL;
+    spv_context context;
+    spv_result_t ret;
+
+    context = spvContextCreate(spv_target_env_from_vkd3d(environment));
+
+    if ((ret = spvValidateBinary(context, spirv->code, spirv->size / sizeof(uint32_t),
+            &diagnostic)))
+    {
+        FIXME("Failed to validate SPIR-V binary, ret %d.\n", ret);
+        FIXME("Diagnostic message: %s.\n", debugstr_a(diagnostic->error));
+    }
+
+    spvDiagnosticDestroy(diagnostic);
+    spvContextDestroy(context);
+}
+
+#else
+
+static uint32_t get_binary_to_text_options(enum vkd3d_shader_compile_option_formatting_flags formatting)
+{
+    return 0;
+}
+static enum vkd3d_result vkd3d_spirv_binary_to_text(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment, uint32_t options, struct vkd3d_shader_code *out)
+{
+    return VKD3D_ERROR;
+}
+static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment) {}
+static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
+        enum vkd3d_shader_spirv_environment environment) {}
+
+#endif  /* HAVE_SPIRV_TOOLS */
+
+static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval,
+        unsigned int index)
+{
+    switch (sysval)
+    {
+        case VKD3D_SHADER_SV_NONE:
+            return VKD3D_SIV_NONE;
+        case VKD3D_SHADER_SV_POSITION:
+            return VKD3D_SIV_POSITION;
+        case VKD3D_SHADER_SV_CLIP_DISTANCE:
+            return VKD3D_SIV_CLIP_DISTANCE;
+        case VKD3D_SHADER_SV_CULL_DISTANCE:
+            return VKD3D_SIV_CULL_DISTANCE;
+        case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE:
+            return VKD3D_SIV_QUAD_U0_TESS_FACTOR + index;
+        case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT:
+            return VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR + index;
+        case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE:
+            return VKD3D_SIV_TRIANGLE_U_TESS_FACTOR + index;
+        case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT:
+            return VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR;
+        case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET:
+            return VKD3D_SIV_LINE_DETAIL_TESS_FACTOR;
+        case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN:
+            return VKD3D_SIV_LINE_DENSITY_TESS_FACTOR;
+        default:
+            FIXME("Unhandled sysval %#x, index %u.\n", sysval, index);
+            return VKD3D_SIV_NONE;
+    }
+}
+
+static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval(enum vkd3d_shader_sysval_semantic sysval)
+{
+      return vkd3d_siv_from_sysval_indexed(sysval, 0);
+}
+
+#define VKD3D_SPIRV_VERSION 0x00010000
+#define VKD3D_SPIRV_GENERATOR_ID 18
+#define VKD3D_SPIRV_GENERATOR_VERSION 2
+#define VKD3D_SPIRV_GENERATOR_MAGIC ((VKD3D_SPIRV_GENERATOR_ID << 16) | VKD3D_SPIRV_GENERATOR_VERSION)
+
+struct vkd3d_spirv_stream
+{
+    uint32_t *words;
+    size_t capacity;
+    size_t word_count;
+
+    struct list inserted_chunks;
+};
+
+static void vkd3d_spirv_stream_init(struct vkd3d_spirv_stream *stream)
+{
+    stream->capacity = 256;
+    if (!(stream->words = vkd3d_calloc(stream->capacity, sizeof(*stream->words))))
+        stream->capacity = 0;
+    stream->word_count = 0;
+
+    list_init(&stream->inserted_chunks);
+}
+
+struct vkd3d_spirv_chunk
+{
+    struct list entry;
+    size_t location;
+    size_t word_count;
+    uint32_t words[];
+};
+
+static void vkd3d_spirv_stream_clear(struct vkd3d_spirv_stream *stream)
+{
+    struct vkd3d_spirv_chunk *c1, *c2;
+
+    stream->word_count = 0;
+
+    LIST_FOR_EACH_ENTRY_SAFE(c1, c2, &stream->inserted_chunks, struct vkd3d_spirv_chunk, entry)
+        vkd3d_free(c1);
+
+    list_init(&stream->inserted_chunks);
+}
+
+static void vkd3d_spirv_stream_free(struct vkd3d_spirv_stream *stream)
+{
+    vkd3d_free(stream->words);
+
+    vkd3d_spirv_stream_clear(stream);
+}
+
+static size_t vkd3d_spirv_stream_current_location(struct vkd3d_spirv_stream *stream)
+{
+    return stream->word_count;
+}
+
+static void vkd3d_spirv_stream_insert(struct vkd3d_spirv_stream *stream,
+        size_t location, const uint32_t *words, unsigned int word_count)
+{
+    struct vkd3d_spirv_chunk *chunk, *current;
+
+    if (!(chunk = vkd3d_malloc(offsetof(struct vkd3d_spirv_chunk, words[word_count]))))
+        return;
+
+    chunk->location = location;
+    chunk->word_count = word_count;
+    memcpy(chunk->words, words, word_count * sizeof(*words));
+
+    LIST_FOR_EACH_ENTRY(current, &stream->inserted_chunks, struct vkd3d_spirv_chunk, entry)
+    {
+        if (current->location > location)
+        {
+            list_add_before(&current->entry, &chunk->entry);
+            return;
+        }
+    }
+
+    list_add_tail(&stream->inserted_chunks, &chunk->entry);
+}
+
+static bool vkd3d_spirv_stream_append(struct vkd3d_spirv_stream *dst_stream,
+        const struct vkd3d_spirv_stream *src_stream)
+{
+    size_t word_count, src_word_count = src_stream->word_count;
+    struct vkd3d_spirv_chunk *chunk;
+    size_t src_location = 0;
+
+    assert(list_empty(&dst_stream->inserted_chunks));
+
+    LIST_FOR_EACH_ENTRY(chunk, &src_stream->inserted_chunks, struct vkd3d_spirv_chunk, entry)
+        src_word_count += chunk->word_count;
+
+    if (!vkd3d_array_reserve((void **)&dst_stream->words, &dst_stream->capacity,
+            dst_stream->word_count + src_word_count, sizeof(*dst_stream->words)))
+        return false;
+
+    assert(dst_stream->word_count + src_word_count <= dst_stream->capacity);
+    LIST_FOR_EACH_ENTRY(chunk, &src_stream->inserted_chunks, struct vkd3d_spirv_chunk, entry)
+    {
+        assert(src_location <= chunk->location);
+        word_count = chunk->location - src_location;
+        memcpy(&dst_stream->words[dst_stream->word_count], &src_stream->words[src_location],
+                word_count * sizeof(*src_stream->words));
+        dst_stream->word_count += word_count;
+        src_location += word_count;
+        assert(src_location == chunk->location);
+
+        memcpy(&dst_stream->words[dst_stream->word_count], chunk->words,
+                chunk->word_count * sizeof(*chunk->words));
+        dst_stream->word_count += chunk->word_count;
+    }
+
+    word_count = src_stream->word_count - src_location;
+    memcpy(&dst_stream->words[dst_stream->word_count], &src_stream->words[src_location],
+            word_count * sizeof(*src_stream->words));
+    dst_stream->word_count += word_count;
+    return true;
+}
+
+struct vkd3d_spirv_builder
+{
+    uint64_t capability_mask;
+    uint64_t capability_draw_parameters : 1;
+    uint64_t capability_demote_to_helper_invocation : 1;
+    uint32_t ext_instr_set_glsl_450;
+    uint32_t invocation_count;
+    SpvExecutionModel execution_model;
+
+    uint32_t current_id;
+    uint32_t main_function_id;
+    struct rb_tree declarations;
+    uint32_t type_sampler_id;
+    uint32_t type_bool_id;
+    uint32_t type_void_id;
+
+    struct vkd3d_spirv_stream debug_stream; /* debug instructions */
+    struct vkd3d_spirv_stream annotation_stream; /* decoration instructions */
+    struct vkd3d_spirv_stream global_stream; /* types, constants, global variables */
+    struct vkd3d_spirv_stream function_stream; /* function definitions */
+
+    struct vkd3d_spirv_stream execution_mode_stream; /* execution mode instructions */
+
+    struct vkd3d_spirv_stream original_function_stream;
+    struct vkd3d_spirv_stream insertion_stream;
+    size_t insertion_location;
+
+    size_t main_function_location;
+
+    /* entry point interface */
+    uint32_t *iface;
+    size_t iface_capacity;
+    size_t iface_element_count;
+};
+
+static uint32_t vkd3d_spirv_alloc_id(struct vkd3d_spirv_builder *builder)
+{
+    return builder->current_id++;
+}
+
+static void vkd3d_spirv_enable_capability(struct vkd3d_spirv_builder *builder,
+        SpvCapability cap)
+{
+    if (cap < sizeof(builder->capability_mask) * CHAR_BIT)
+    {
+        builder->capability_mask |= 1ull << cap;
+    }
+    else if (cap == SpvCapabilityDrawParameters)
+    {
+        builder->capability_draw_parameters = 1;
+    }
+    else if (cap == SpvCapabilityDemoteToHelperInvocationEXT)
+    {
+        builder->capability_demote_to_helper_invocation = 1;
+    }
+    else
+    {
+        FIXME("Unhandled capability %#x.\n", cap);
+    }
+}
+
+static uint32_t vkd3d_spirv_get_glsl_std450_instr_set(struct vkd3d_spirv_builder *builder)
+{
+    if (!builder->ext_instr_set_glsl_450)
+        builder->ext_instr_set_glsl_450 = vkd3d_spirv_alloc_id(builder);
+
+    return builder->ext_instr_set_glsl_450;
+}
+
+static void vkd3d_spirv_add_iface_variable(struct vkd3d_spirv_builder *builder,
+        uint32_t id)
+{
+    if (!vkd3d_array_reserve((void **)&builder->iface, &builder->iface_capacity,
+            builder->iface_element_count + 1, sizeof(*builder->iface)))
+        return;
+
+    builder->iface[builder->iface_element_count++] = id;
+}
+
+static void vkd3d_spirv_set_execution_model(struct vkd3d_spirv_builder *builder,
+        SpvExecutionModel model)
+{
+    builder->execution_model = model;
+
+    switch (model)
+    {
+        case SpvExecutionModelVertex:
+        case SpvExecutionModelFragment:
+        case SpvExecutionModelGLCompute:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityShader);
+            break;
+        case SpvExecutionModelTessellationControl:
+        case SpvExecutionModelTessellationEvaluation:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityTessellation);
+            break;
+        case SpvExecutionModelGeometry:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
+            break;
+        default:
+            ERR("Unhandled execution model %#x.\n", model);
+    }
+}
+
+static uint32_t vkd3d_spirv_opcode_word(SpvOp op, unsigned int word_count)
+{
+    assert(!(op & ~SpvOpCodeMask));
+    return (word_count << SpvWordCountShift) | op;
+}
+
+static void vkd3d_spirv_build_word(struct vkd3d_spirv_stream *stream, uint32_t word)
+{
+    if (!vkd3d_array_reserve((void **)&stream->words, &stream->capacity,
+            stream->word_count + 1, sizeof(*stream->words)))
+        return;
+
+    stream->words[stream->word_count++] = word;
+}
+
+static unsigned int vkd3d_spirv_string_word_count(const char *str)
+{
+    return align(strlen(str) + 1, sizeof(uint32_t)) / sizeof(uint32_t);
+}
+
+static void vkd3d_spirv_build_string(struct vkd3d_spirv_stream *stream,
+        const char *str, unsigned int word_count)
+{
+    unsigned int word_idx, i;
+    const char *ptr = str;
+
+    for (word_idx = 0; word_idx < word_count; ++word_idx)
+    {
+        uint32_t word = 0;
+        for (i = 0; i < sizeof(uint32_t) && *ptr; ++i)
+            word |= (uint32_t)*ptr++ << (8 * i);
+        vkd3d_spirv_build_word(stream, word);
+    }
+}
+
+typedef uint32_t (*vkd3d_spirv_build_pfn)(struct vkd3d_spirv_builder *builder);
+typedef uint32_t (*vkd3d_spirv_build1_pfn)(struct vkd3d_spirv_builder *builder,
+        uint32_t operand0);
+typedef uint32_t (*vkd3d_spirv_build1v_pfn)(struct vkd3d_spirv_builder *builder,
+        uint32_t operand0, const uint32_t *operands, unsigned int operand_count);
+typedef uint32_t (*vkd3d_spirv_build2_pfn)(struct vkd3d_spirv_builder *builder,
+        uint32_t operand0, uint32_t operand1);
+typedef uint32_t (*vkd3d_spirv_build7_pfn)(struct vkd3d_spirv_builder *builder,
+        uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand3,
+        uint32_t operand4, uint32_t operand5, uint32_t operand6);
+
+static uint32_t vkd3d_spirv_build_once(struct vkd3d_spirv_builder *builder,
+        uint32_t *id, vkd3d_spirv_build_pfn build_pfn)
+{
+    if (!(*id))
+        *id = build_pfn(builder);
+    return *id;
+}
+
+#define MAX_SPIRV_DECLARATION_PARAMETER_COUNT 7
+
+struct vkd3d_spirv_declaration
+{
+    struct rb_entry entry;
+
+    SpvOp op;
+    unsigned int parameter_count;
+    uint32_t parameters[MAX_SPIRV_DECLARATION_PARAMETER_COUNT];
+    uint32_t id;
+};
+
+static int vkd3d_spirv_declaration_compare(const void *key, const struct rb_entry *e)
+{
+    const struct vkd3d_spirv_declaration *a = key;
+    const struct vkd3d_spirv_declaration *b = RB_ENTRY_VALUE(e, const struct vkd3d_spirv_declaration, entry);
+
+    if (a->op != b->op)
+        return a->op - b->op;
+    if (a->parameter_count != b->parameter_count)
+        return a->parameter_count - b->parameter_count;
+    assert(a->parameter_count <= ARRAY_SIZE(a->parameters));
+    return memcmp(&a->parameters, &b->parameters, a->parameter_count * sizeof(*a->parameters));
+}
+
+static void vkd3d_spirv_declaration_free(struct rb_entry *entry, void *context)
+{
+    struct vkd3d_spirv_declaration *d = RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry);
+
+    vkd3d_free(d);
+}
+
+static void vkd3d_spirv_insert_declaration(struct vkd3d_spirv_builder *builder,
+        const struct vkd3d_spirv_declaration *declaration)
+{
+    struct vkd3d_spirv_declaration *d;
+
+    assert(declaration->parameter_count <= ARRAY_SIZE(declaration->parameters));
+
+    if (!(d = vkd3d_malloc(sizeof(*d))))
+        return;
+    memcpy(d, declaration, sizeof(*d));
+    if (rb_put(&builder->declarations, d, &d->entry) == -1)
+    {
+        ERR("Failed to insert declaration entry.\n");
+        vkd3d_free(d);
+    }
+}
+
+static uint32_t vkd3d_spirv_build_once1(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t operand0, vkd3d_spirv_build1_pfn build_pfn)
+{
+    struct vkd3d_spirv_declaration declaration;
+    struct rb_entry *entry;
+
+    declaration.op = op;
+    declaration.parameter_count = 1;
+    declaration.parameters[0] = operand0;
+
+    if ((entry = rb_get(&builder->declarations, &declaration)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
+
+    declaration.id = build_pfn(builder, operand0);
+    vkd3d_spirv_insert_declaration(builder, &declaration);
+    return declaration.id;
+}
+
+static uint32_t vkd3d_spirv_build_once1v(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t operand0, const uint32_t *operands, unsigned int operand_count,
+        vkd3d_spirv_build1v_pfn build_pfn)
+{
+    struct vkd3d_spirv_declaration declaration;
+    unsigned int i, param_idx = 0;
+    struct rb_entry *entry;
+
+    if (operand_count >= ARRAY_SIZE(declaration.parameters))
+    {
+        WARN("Unsupported parameter count %u (opcode %#x).\n", operand_count + 1, op);
+        return build_pfn(builder, operand0, operands, operand_count);
+    }
+
+    declaration.op = op;
+    declaration.parameters[param_idx++] = operand0;
+    for (i = 0; i < operand_count; ++i)
+        declaration.parameters[param_idx++] = operands[i];
+    declaration.parameter_count = param_idx;
+
+    if ((entry = rb_get(&builder->declarations, &declaration)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
+
+    declaration.id = build_pfn(builder, operand0, operands, operand_count);
+    vkd3d_spirv_insert_declaration(builder, &declaration);
+    return declaration.id;
+}
+
+static uint32_t vkd3d_spirv_build_once2(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t operand0, uint32_t operand1, vkd3d_spirv_build2_pfn build_pfn)
+{
+    struct vkd3d_spirv_declaration declaration;
+    struct rb_entry *entry;
+
+    declaration.op = op;
+    declaration.parameter_count = 2;
+    declaration.parameters[0] = operand0;
+    declaration.parameters[1] = operand1;
+
+    if ((entry = rb_get(&builder->declarations, &declaration)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
+
+    declaration.id = build_pfn(builder, operand0, operand1);
+    vkd3d_spirv_insert_declaration(builder, &declaration);
+    return declaration.id;
+}
+
+static uint32_t vkd3d_spirv_build_once7(struct vkd3d_spirv_builder *builder,
+        SpvOp op, const uint32_t *operands, vkd3d_spirv_build7_pfn build_pfn)
+{
+    struct vkd3d_spirv_declaration declaration;
+    struct rb_entry *entry;
+
+    declaration.op = op;
+    declaration.parameter_count = 7;
+    memcpy(&declaration.parameters, operands, declaration.parameter_count * sizeof(*operands));
+
+    if ((entry = rb_get(&builder->declarations, &declaration)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
+
+    declaration.id = build_pfn(builder, operands[0], operands[1], operands[2],
+            operands[3], operands[4], operands[5], operands[6]);
+    vkd3d_spirv_insert_declaration(builder, &declaration);
+    return declaration.id;
+}
+
+/*
+ * vkd3d_spirv_build_op[1-3][v]()
+ * vkd3d_spirv_build_op_[t][r][1-3][v]()
+ *
+ * t   - result type
+ * r   - result id
+ * 1-3 - the number of operands
+ * v   - variable number of operands
+ */
+static void vkd3d_spirv_build_op(struct vkd3d_spirv_stream *stream, SpvOp op)
+{
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 1));
+}
+
+static void vkd3d_spirv_build_op1(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand)
+{
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 2));
+    vkd3d_spirv_build_word(stream, operand);
+}
+
+static void vkd3d_spirv_build_op1v(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, const uint32_t *operands, unsigned int operand_count)
+{
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 2 + operand_count));
+    vkd3d_spirv_build_word(stream, operand0);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+}
+
+static void vkd3d_spirv_build_op2v(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, uint32_t operand1,
+        const uint32_t *operands, unsigned int operand_count)
+{
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 3 + operand_count));
+    vkd3d_spirv_build_word(stream, operand0);
+    vkd3d_spirv_build_word(stream, operand1);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+}
+
+static void vkd3d_spirv_build_op3v(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, uint32_t operand1, uint32_t operand2,
+        const uint32_t *operands, unsigned int operand_count)
+{
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 4 + operand_count));
+    vkd3d_spirv_build_word(stream, operand0);
+    vkd3d_spirv_build_word(stream, operand1);
+    vkd3d_spirv_build_word(stream, operand2);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+}
+
+static void vkd3d_spirv_build_op2(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, NULL, 0);
+}
+
+static void vkd3d_spirv_build_op3(struct vkd3d_spirv_stream *stream,
+        SpvOp op, uint32_t operand0, uint32_t operand1, uint32_t operand2)
+{
+    return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, &operand2, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_rv(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op,
+        const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = vkd3d_spirv_alloc_id(builder);
+    vkd3d_spirv_build_op1v(stream, op, result_id, operands, operand_count);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_r(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op)
+{
+    return vkd3d_spirv_build_op_rv(builder, stream, op, NULL, 0);
+}
+
+static uint32_t vkd3d_spirv_build_op_r1(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0)
+{
+    return vkd3d_spirv_build_op_rv(builder, stream, op, &operand0, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_r2(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0, uint32_t operand1)
+{
+    uint32_t operands[] = {operand0, operand1};
+    return vkd3d_spirv_build_op_rv(builder, stream, op, operands, ARRAY_SIZE(operands));
+}
+
+static uint32_t vkd3d_spirv_build_op_r1v(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0,
+        const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = vkd3d_spirv_alloc_id(builder);
+    vkd3d_spirv_build_op2v(stream, op, result_id, operand0, operands, operand_count);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_trv(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = vkd3d_spirv_alloc_id(builder);
+    vkd3d_spirv_build_op2v(stream, op, result_type, result_id, operands, operand_count);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_tr(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type)
+{
+    return vkd3d_spirv_build_op_trv(builder, stream, op, result_type, NULL, 0);
+}
+
+static uint32_t vkd3d_spirv_build_op_tr1(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0)
+{
+    return vkd3d_spirv_build_op_trv(builder, stream, op, result_type, &operand0, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_tr2(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, uint32_t operand1)
+{
+    uint32_t operands[] = {operand0, operand1};
+    return vkd3d_spirv_build_op_trv(builder, stream, op, result_type,
+            operands, ARRAY_SIZE(operands));
+}
+
+static uint32_t vkd3d_spirv_build_op_tr3(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, uint32_t operand1, uint32_t operand2)
+{
+    uint32_t operands[] = {operand0, operand1, operand2};
+    return vkd3d_spirv_build_op_trv(builder, stream, op, result_type,
+            operands, ARRAY_SIZE(operands));
+}
+
+static uint32_t vkd3d_spirv_build_op_tr1v(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = vkd3d_spirv_alloc_id(builder);
+    vkd3d_spirv_build_op3v(stream, op, result_type, result_id, operand0, operands, operand_count);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_tr2v(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
+        uint32_t operand0, uint32_t operand1, const uint32_t *operands, unsigned int operand_count)
+{
+    uint32_t result_id = vkd3d_spirv_alloc_id(builder);
+    unsigned int i;
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 5 + operand_count));
+    vkd3d_spirv_build_word(stream, result_type);
+    vkd3d_spirv_build_word(stream, result_id);
+    vkd3d_spirv_build_word(stream, operand0);
+    vkd3d_spirv_build_word(stream, operand1);
+    for (i = 0; i < operand_count; ++i)
+        vkd3d_spirv_build_word(stream, operands[i]);
+    return result_id;
+}
+
+static void vkd3d_spirv_begin_function_stream_insertion(struct vkd3d_spirv_builder *builder,
+        size_t location)
+{
+    assert(builder->insertion_location == ~(size_t)0);
+
+    if (vkd3d_spirv_stream_current_location(&builder->function_stream) == location)
+        return;
+
+    builder->original_function_stream = builder->function_stream;
+    builder->function_stream = builder->insertion_stream;
+    builder->insertion_location = location;
+}
+
+static void vkd3d_spirv_end_function_stream_insertion(struct vkd3d_spirv_builder *builder)
+{
+    struct vkd3d_spirv_stream *insertion_stream = &builder->insertion_stream;
+
+    if (builder->insertion_location == ~(size_t)0)
+        return;
+
+    builder->insertion_stream = builder->function_stream;
+    builder->function_stream = builder->original_function_stream;
+
+    vkd3d_spirv_stream_insert(&builder->function_stream, builder->insertion_location,
+            insertion_stream->words, insertion_stream->word_count);
+    vkd3d_spirv_stream_clear(insertion_stream);
+    builder->insertion_location = ~(size_t)0;
+}
+
+struct vkd3d_spirv_op_branch_conditional
+{
+    uint32_t opcode;
+    uint32_t condition_id;
+    uint32_t true_label;
+    uint32_t false_label;
+};
+
+static struct vkd3d_spirv_op_branch_conditional *vkd3d_spirv_as_op_branch_conditional(
+        struct vkd3d_spirv_stream *stream, size_t location)
+{
+    return (struct vkd3d_spirv_op_branch_conditional *)&stream->words[location];
+}
+
+static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream,
+        SpvCapability cap)
+{
+    vkd3d_spirv_build_op1(stream, SpvOpCapability, cap);
+}
+
+static void vkd3d_spirv_build_op_extension(struct vkd3d_spirv_stream *stream,
+        const char *name)
+{
+    unsigned int name_size = vkd3d_spirv_string_word_count(name);
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpExtension, 1 + name_size));
+    vkd3d_spirv_build_string(stream, name, name_size);
+}
+
+static void vkd3d_spirv_build_op_ext_inst_import(struct vkd3d_spirv_stream *stream,
+        uint32_t result_id, const char *name)
+{
+    unsigned int name_size = vkd3d_spirv_string_word_count(name);
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpExtInstImport, 2 + name_size));
+    vkd3d_spirv_build_word(stream, result_id);
+    vkd3d_spirv_build_string(stream, name, name_size);
+}
+
+static uint32_t vkd3d_spirv_build_op_ext_inst(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t inst_set, uint32_t inst_number,
+        uint32_t *operands, unsigned int operand_count)
+{
+    return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream,
+            SpvOpExtInst, result_type, inst_set, inst_number, operands, operand_count);
+}
+
+static void vkd3d_spirv_build_op_memory_model(struct vkd3d_spirv_stream *stream,
+        SpvAddressingModel addressing_model, SpvMemoryModel memory_model)
+{
+    vkd3d_spirv_build_op2(stream, SpvOpMemoryModel, addressing_model, memory_model);
+}
+
+static void vkd3d_spirv_build_op_entry_point(struct vkd3d_spirv_stream *stream,
+        SpvExecutionModel model, uint32_t function_id, const char *name,
+        uint32_t *interface_list, unsigned int interface_size)
+{
+    unsigned int i, name_size = vkd3d_spirv_string_word_count(name);
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpEntryPoint, 3 + name_size + interface_size));
+    vkd3d_spirv_build_word(stream, model);
+    vkd3d_spirv_build_word(stream, function_id);
+    vkd3d_spirv_build_string(stream, name, name_size);
+    for (i = 0; i < interface_size; ++i)
+        vkd3d_spirv_build_word(stream, interface_list[i]);
+}
+
+static void vkd3d_spirv_build_op_execution_mode(struct vkd3d_spirv_stream *stream,
+        uint32_t entry_point, SpvExecutionMode mode, const uint32_t *literals, unsigned int literal_count)
+{
+    vkd3d_spirv_build_op2v(stream, SpvOpExecutionMode, entry_point, mode, literals, literal_count);
+}
+
+static void vkd3d_spirv_build_op_name(struct vkd3d_spirv_builder *builder,
+        uint32_t id, const char *fmt, ...)
+{
+    struct vkd3d_spirv_stream *stream = &builder->debug_stream;
+    unsigned int name_size;
+    char name[1024];
+    va_list args;
+
+    va_start(args, fmt);
+    vsnprintf(name, ARRAY_SIZE(name), fmt, args);
+    name[ARRAY_SIZE(name) - 1] = '\0';
+    va_end(args);
+
+    name_size = vkd3d_spirv_string_word_count(name);
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpName, 2 + name_size));
+    vkd3d_spirv_build_word(stream, id);
+    vkd3d_spirv_build_string(stream, name, name_size);
+}
+
+static void vkd3d_spirv_build_op_member_name(struct vkd3d_spirv_builder *builder,
+        uint32_t type_id, uint32_t member, const char *fmt, ...)
+{
+    struct vkd3d_spirv_stream *stream = &builder->debug_stream;
+    unsigned int name_size;
+    char name[1024];
+    va_list args;
+
+    va_start(args, fmt);
+    vsnprintf(name, ARRAY_SIZE(name), fmt, args);
+    name[ARRAY_SIZE(name) - 1] = '\0';
+    va_end(args);
+
+    name_size = vkd3d_spirv_string_word_count(name);
+    vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpMemberName, 3 + name_size));
+    vkd3d_spirv_build_word(stream, type_id);
+    vkd3d_spirv_build_word(stream, member);
+    vkd3d_spirv_build_string(stream, name, name_size);
+}
+
+static void vkd3d_spirv_build_op_decorate(struct vkd3d_spirv_builder *builder,
+        uint32_t target_id, SpvDecoration decoration,
+        uint32_t *literals, uint32_t literal_count)
+{
+    vkd3d_spirv_build_op2v(&builder->annotation_stream,
+            SpvOpDecorate, target_id, decoration, literals, literal_count);
+}
+
+static void vkd3d_spirv_build_op_decorate1(struct vkd3d_spirv_builder *builder,
+        uint32_t target_id, SpvDecoration decoration, uint32_t operand0)
+{
+    return vkd3d_spirv_build_op_decorate(builder, target_id, decoration, &operand0, 1);
+}
+
+static void vkd3d_spirv_build_op_member_decorate(struct vkd3d_spirv_builder *builder,
+        uint32_t structure_type_id, uint32_t member_idx, SpvDecoration decoration,
+        uint32_t *literals, uint32_t literal_count)
+{
+    vkd3d_spirv_build_op3v(&builder->annotation_stream, SpvOpMemberDecorate,
+            structure_type_id, member_idx, decoration, literals, literal_count);
+}
+
+static void vkd3d_spirv_build_op_member_decorate1(struct vkd3d_spirv_builder *builder,
+        uint32_t structure_type_id, uint32_t member_idx, SpvDecoration decoration, uint32_t operand0)
+{
+    vkd3d_spirv_build_op_member_decorate(builder, structure_type_id, member_idx, decoration, &operand0, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_void(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeVoid);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_void(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_once(builder, &builder->type_void_id, vkd3d_spirv_build_op_type_void);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_bool(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeBool);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_bool(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_once(builder, &builder->type_bool_id, vkd3d_spirv_build_op_type_bool);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_float(struct vkd3d_spirv_builder *builder,
+        uint32_t width)
+{
+    return vkd3d_spirv_build_op_r1(builder, &builder->global_stream, SpvOpTypeFloat, width);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_float(struct vkd3d_spirv_builder *builder,
+        uint32_t width)
+{
+    return vkd3d_spirv_build_once1(builder, SpvOpTypeFloat, width, vkd3d_spirv_build_op_type_float);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_int(struct vkd3d_spirv_builder *builder,
+        uint32_t width, uint32_t signedness)
+{
+    return vkd3d_spirv_build_op_r2(builder, &builder->global_stream, SpvOpTypeInt, width, signedness);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_int(struct vkd3d_spirv_builder *builder,
+        uint32_t width, uint32_t signedness)
+{
+    return vkd3d_spirv_build_once2(builder, SpvOpTypeInt, width, signedness,
+            vkd3d_spirv_build_op_type_int);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_vector(struct vkd3d_spirv_builder *builder,
+        uint32_t component_type, uint32_t component_count)
+{
+    return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
+            SpvOpTypeVector, component_type, component_count);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_vector(struct vkd3d_spirv_builder *builder,
+        uint32_t component_type, uint32_t component_count)
+{
+    return vkd3d_spirv_build_once2(builder, SpvOpTypeVector, component_type, component_count,
+            vkd3d_spirv_build_op_type_vector);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_array(struct vkd3d_spirv_builder *builder,
+        uint32_t element_type, uint32_t length_id)
+{
+    return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
+            SpvOpTypeArray, element_type, length_id);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_array(struct vkd3d_spirv_builder *builder,
+        uint32_t element_type, uint32_t length_id)
+{
+    return vkd3d_spirv_build_once2(builder, SpvOpTypeArray, element_type, length_id,
+            vkd3d_spirv_build_op_type_array);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_runtime_array(struct vkd3d_spirv_builder *builder, uint32_t element_type)
+{
+    return vkd3d_spirv_build_op_r1(builder, &builder->global_stream, SpvOpTypeRuntimeArray, element_type);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_runtime_array(struct vkd3d_spirv_builder *builder, uint32_t element_type)
+{
+    return vkd3d_spirv_build_once1(builder, SpvOpTypeRuntimeArray,
+            element_type, vkd3d_spirv_build_op_type_runtime_array);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_struct(struct vkd3d_spirv_builder *builder,
+        uint32_t *members, unsigned int member_count)
+{
+    return vkd3d_spirv_build_op_rv(builder, &builder->global_stream,
+            SpvOpTypeStruct, members, member_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_sampler(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeSampler);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_sampler(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_once(builder, &builder->type_sampler_id, vkd3d_spirv_build_op_type_sampler);
+}
+
+/* Access qualifiers are not supported. */
+static uint32_t vkd3d_spirv_build_op_type_image(struct vkd3d_spirv_builder *builder,
+        uint32_t sampled_type_id, SpvDim dim, uint32_t depth, uint32_t arrayed,
+        uint32_t ms, uint32_t sampled, SpvImageFormat format)
+{
+    uint32_t operands[] = {sampled_type_id, dim, depth, arrayed, ms, sampled, format};
+    return vkd3d_spirv_build_op_rv(builder, &builder->global_stream,
+            SpvOpTypeImage, operands, ARRAY_SIZE(operands));
+}
+
+static uint32_t vkd3d_spirv_get_op_type_image(struct vkd3d_spirv_builder *builder,
+        uint32_t sampled_type_id, SpvDim dim, uint32_t depth, uint32_t arrayed,
+        uint32_t ms, uint32_t sampled, SpvImageFormat format)
+{
+    uint32_t operands[] = {sampled_type_id, dim, depth, arrayed, ms, sampled, format};
+    return vkd3d_spirv_build_once7(builder, SpvOpTypeImage, operands,
+            vkd3d_spirv_build_op_type_image);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_sampled_image(struct vkd3d_spirv_builder *builder,
+        uint32_t image_type_id)
+{
+    return vkd3d_spirv_build_op_r1(builder, &builder->global_stream,
+            SpvOpTypeSampledImage, image_type_id);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_sampled_image(struct vkd3d_spirv_builder *builder,
+        uint32_t image_type_id)
+{
+    return vkd3d_spirv_build_once1(builder, SpvOpTypeSampledImage, image_type_id,
+            vkd3d_spirv_build_op_type_sampled_image);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_function(struct vkd3d_spirv_builder *builder,
+        uint32_t return_type, const uint32_t *param_types, unsigned int param_count)
+{
+    return vkd3d_spirv_build_op_r1v(builder, &builder->global_stream,
+            SpvOpTypeFunction, return_type, param_types, param_count);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_function(struct vkd3d_spirv_builder *builder,
+        uint32_t return_type, const uint32_t *param_types, unsigned int param_count)
+{
+    return vkd3d_spirv_build_once1v(builder, SpvOpTypeFunction, return_type,
+            param_types, param_count, vkd3d_spirv_build_op_type_function);
+}
+
+static uint32_t vkd3d_spirv_build_op_type_pointer(struct vkd3d_spirv_builder *builder,
+        uint32_t storage_class, uint32_t type_id)
+{
+    return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
+            SpvOpTypePointer, storage_class, type_id);
+}
+
+static uint32_t vkd3d_spirv_get_op_type_pointer(struct vkd3d_spirv_builder *builder,
+        uint32_t storage_class, uint32_t type_id)
+{
+    return vkd3d_spirv_build_once2(builder, SpvOpTypePointer, storage_class, type_id,
+            vkd3d_spirv_build_op_type_pointer);
+}
+
+/* Types larger than 32-bits are not supported. */
+static uint32_t vkd3d_spirv_build_op_constant(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t value)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->global_stream,
+            SpvOpConstant, result_type, value);
+}
+
+static uint32_t vkd3d_spirv_get_op_constant(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t value)
+{
+    return vkd3d_spirv_build_once2(builder, SpvOpConstant, result_type, value,
+            vkd3d_spirv_build_op_constant);
+}
+
+static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count)
+{
+    return vkd3d_spirv_build_op_trv(builder, &builder->global_stream,
+            SpvOpConstantComposite, result_type, constituents, constituent_count);
+}
+
+static uint32_t vkd3d_spirv_get_op_constant_composite(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count)
+{
+    return vkd3d_spirv_build_once1v(builder, SpvOpConstantComposite, result_type,
+            constituents, constituent_count, vkd3d_spirv_build_op_constant_composite);
+}
+
+static uint32_t vkd3d_spirv_build_op_spec_constant(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t value)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->global_stream,
+            SpvOpSpecConstant, result_type, value);
+}
+
+static uint32_t vkd3d_spirv_build_op_variable(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, uint32_t type_id, uint32_t storage_class, uint32_t initializer)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, stream,
+            SpvOpVariable, type_id, storage_class, &initializer, !!initializer);
+}
+
+static uint32_t vkd3d_spirv_build_op_function(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t result_id, uint32_t function_control, uint32_t function_type)
+{
+    vkd3d_spirv_build_op3v(&builder->function_stream,
+            SpvOpFunction, result_type, result_id, function_control, &function_type, 1);
+    return result_id;
+}
+
+static uint32_t vkd3d_spirv_build_op_function_parameter(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type)
+{
+    return vkd3d_spirv_build_op_tr(builder, &builder->function_stream,
+            SpvOpFunctionParameter, result_type);
+}
+
+static void vkd3d_spirv_build_op_function_end(struct vkd3d_spirv_builder *builder)
+{
+    vkd3d_spirv_build_op(&builder->function_stream, SpvOpFunctionEnd);
+}
+
+static uint32_t vkd3d_spirv_build_op_function_call(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t function_id, const uint32_t *arguments, unsigned int argument_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
+            SpvOpFunctionCall, result_type, function_id, arguments, argument_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_undef(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_spirv_stream *stream, uint32_t type_id)
+{
+    return vkd3d_spirv_build_op_tr(builder, stream, SpvOpUndef, type_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_access_chain(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
+            SpvOpAccessChain, result_type, base_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_access_chain1(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t index)
+{
+    return vkd3d_spirv_build_op_access_chain(builder, result_type, base_id, &index, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_in_bounds_access_chain(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
+            SpvOpInBoundsAccessChain, result_type, base_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_in_bounds_access_chain1(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base_id, uint32_t index)
+{
+    return vkd3d_spirv_build_op_in_bounds_access_chain(builder, result_type, base_id, &index, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_vector_shuffle(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t vector1_id, uint32_t vector2_id,
+        const uint32_t *components, uint32_t component_count)
+{
+    return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream, SpvOpVectorShuffle,
+            result_type, vector1_id, vector2_id, components, component_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_composite_construct(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count)
+{
+    return vkd3d_spirv_build_op_trv(builder, &builder->function_stream, SpvOpCompositeConstruct,
+            result_type, constituents, constituent_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_composite_extract(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t composite_id, const uint32_t *indexes, unsigned int index_count)
+{
+    return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream, SpvOpCompositeExtract,
+            result_type, composite_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_composite_extract1(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t composite_id, uint32_t index)
+{
+    return vkd3d_spirv_build_op_composite_extract(builder, result_type, composite_id, &index, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_composite_insert(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t object_id, uint32_t composite_id,
+        const uint32_t *indexes, unsigned int index_count)
+{
+    return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream, SpvOpCompositeInsert,
+            result_type, object_id, composite_id, indexes, index_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_composite_insert1(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t object_id, uint32_t composite_id, uint32_t index)
+{
+    return vkd3d_spirv_build_op_composite_insert(builder, result_type, object_id, composite_id, &index, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_load(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t pointer_id, uint32_t memory_access)
+{
+    if (!memory_access)
+        return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpLoad,
+                result_type, pointer_id);
+    else
+        return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpLoad,
+                result_type, pointer_id, memory_access);
+}
+
+static void vkd3d_spirv_build_op_store(struct vkd3d_spirv_builder *builder,
+        uint32_t pointer_id, uint32_t object_id, uint32_t memory_access)
+{
+    if (!memory_access)
+        return vkd3d_spirv_build_op2(&builder->function_stream, SpvOpStore,
+                pointer_id, object_id);
+    else
+        return vkd3d_spirv_build_op3(&builder->function_stream, SpvOpStore,
+                pointer_id, object_id, memory_access);
+}
+
+static void vkd3d_spirv_build_op_copy_memory(struct vkd3d_spirv_builder *builder,
+        uint32_t target_id, uint32_t source_id, uint32_t memory_access)
+{
+    if (!memory_access)
+        return vkd3d_spirv_build_op2(&builder->function_stream, SpvOpCopyMemory,
+                target_id, source_id);
+    else
+        return vkd3d_spirv_build_op3(&builder->function_stream, SpvOpCopyMemory,
+                target_id, source_id, memory_access);
+}
+
+static uint32_t vkd3d_spirv_build_op_select(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t condition_id, uint32_t object0_id, uint32_t object1_id)
+{
+    return vkd3d_spirv_build_op_tr3(builder, &builder->function_stream,
+            SpvOpSelect, result_type, condition_id, object0_id, object1_id);
+}
+
+static void vkd3d_spirv_build_op_kill(struct vkd3d_spirv_builder *builder)
+{
+    vkd3d_spirv_build_op(&builder->function_stream, SpvOpKill);
+}
+
+static void vkd3d_spirv_build_op_demote_to_helper_invocation(struct vkd3d_spirv_builder *builder)
+{
+    vkd3d_spirv_build_op(&builder->function_stream, SpvOpDemoteToHelperInvocationEXT);
+}
+
+static void vkd3d_spirv_build_op_return(struct vkd3d_spirv_builder *builder)
+{
+    vkd3d_spirv_build_op(&builder->function_stream, SpvOpReturn);
+}
+
+static uint32_t vkd3d_spirv_build_op_label(struct vkd3d_spirv_builder *builder,
+        uint32_t label_id)
+{
+    vkd3d_spirv_build_op1(&builder->function_stream, SpvOpLabel, label_id);
+    return label_id;
+}
+
+/* Loop control parameters are not supported. */
+static void vkd3d_spirv_build_op_loop_merge(struct vkd3d_spirv_builder *builder,
+        uint32_t merge_block, uint32_t continue_target, SpvLoopControlMask loop_control)
+{
+    vkd3d_spirv_build_op3(&builder->function_stream, SpvOpLoopMerge,
+            merge_block, continue_target, loop_control);
+}
+
+static void vkd3d_spirv_build_op_selection_merge(struct vkd3d_spirv_builder *builder,
+        uint32_t merge_block, uint32_t selection_control)
+{
+    vkd3d_spirv_build_op2(&builder->function_stream, SpvOpSelectionMerge,
+            merge_block, selection_control);
+}
+
+static void vkd3d_spirv_build_op_branch(struct vkd3d_spirv_builder *builder, uint32_t label)
+{
+    vkd3d_spirv_build_op1(&builder->function_stream, SpvOpBranch, label);
+}
+
+/* Branch weights are not supported. */
+static void vkd3d_spirv_build_op_branch_conditional(struct vkd3d_spirv_builder *builder,
+        uint32_t condition, uint32_t true_label, uint32_t false_label)
+{
+    vkd3d_spirv_build_op3(&builder->function_stream, SpvOpBranchConditional,
+            condition, true_label, false_label);
+}
+
+static void vkd3d_spirv_build_op_switch(struct vkd3d_spirv_builder *builder,
+        uint32_t selector, uint32_t default_label, uint32_t *targets, unsigned int target_count)
+{
+    vkd3d_spirv_build_op2v(&builder->function_stream, SpvOpSwitch,
+            selector, default_label, targets, 2 * target_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_iadd(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpIAdd, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_imul(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpIMul, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_udiv(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpUDiv, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_umod(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpUMod, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_isub(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpISub, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_fdiv(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpFDiv, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_fnegate(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpFNegate, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_snegate(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpSNegate, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_and(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpBitwiseAnd, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_shift_left_logical(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base, uint32_t shift)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpShiftLeftLogical, result_type, base, shift);
+}
+
+static uint32_t vkd3d_spirv_build_op_shift_right_logical(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t base, uint32_t shift)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpShiftRightLogical, result_type, base, shift);
+}
+
+static uint32_t vkd3d_spirv_build_op_logical_and(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpLogicalAnd, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_uless_than(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpULessThan, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_uless_than_equal(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpULessThanEqual, result_type, operand0, operand1);
+}
+
+static uint32_t vkd3d_spirv_build_op_convert_utof(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t unsigned_value)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpConvertUToF, result_type, unsigned_value);
+}
+
+static uint32_t vkd3d_spirv_build_op_bitcast(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpBitcast, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_texel_pointer(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t coordinate_id, uint32_t sample_id)
+{
+    return vkd3d_spirv_build_op_tr3(builder, &builder->function_stream,
+            SpvOpImageTexelPointer, result_type, image_id, coordinate_id, sample_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_sampled_image(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t sampler_id)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpSampledImage, result_type, image_id, sampler_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t sampled_image_id)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpImage, result_type, sampled_image_id);
+}
+
+static uint32_t vkd3d_spirv_build_image_instruction(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t result_type, const uint32_t *operands, unsigned int operand_count,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    unsigned int index = 0, i;
+    uint32_t w[10];
+
+    assert(operand_count <= ARRAY_SIZE(w));
+    for (i = 0; i < operand_count; ++i)
+        w[index++] = operands[i];
+
+    if (image_operands_mask)
+    {
+        assert(index + 1 + image_operand_count <= ARRAY_SIZE(w));
+        w[index++] = image_operands_mask;
+        for (i = 0; i < image_operand_count; ++i)
+            w[index++] = image_operands[i];
+    }
+
+    return vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
+            op, result_type, w, index);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_sample(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t result_type, uint32_t sampled_image_id, uint32_t coordinate_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {sampled_image_id, coordinate_id};
+
+    if (op == SpvOpImageSampleExplicitLod)
+        assert(image_operands_mask & (SpvImageOperandsLodMask | SpvImageOperandsGradMask));
+    else
+        assert(op == SpvOpImageSampleImplicitLod);
+
+    return vkd3d_spirv_build_image_instruction(builder, op, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_sample_dref(struct vkd3d_spirv_builder *builder,
+        SpvOp op, uint32_t result_type, uint32_t sampled_image_id, uint32_t coordinate_id, uint32_t dref_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {sampled_image_id, coordinate_id, dref_id};
+
+    if (op == SpvOpImageSampleDrefExplicitLod)
+        assert(image_operands_mask & (SpvImageOperandsLodMask | SpvImageOperandsGradMask));
+    else
+        assert(op == SpvOpImageSampleDrefImplicitLod);
+
+    return vkd3d_spirv_build_image_instruction(builder, op, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_gather(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t sampled_image_id, uint32_t coordinate_id, uint32_t component_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {sampled_image_id, coordinate_id, component_id};
+    return vkd3d_spirv_build_image_instruction(builder, SpvOpImageGather, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_dref_gather(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t sampled_image_id, uint32_t coordinate_id, uint32_t dref_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {sampled_image_id, coordinate_id, dref_id};
+    return vkd3d_spirv_build_image_instruction(builder, SpvOpImageDrefGather, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_fetch(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t coordinate_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {image_id, coordinate_id};
+    return vkd3d_spirv_build_image_instruction(builder, SpvOpImageFetch, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_read(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t coordinate_id,
+        uint32_t image_operands_mask, const uint32_t *image_operands, unsigned int image_operand_count)
+{
+    const uint32_t operands[] = {image_id, coordinate_id};
+    return vkd3d_spirv_build_image_instruction(builder, SpvOpImageRead, result_type,
+            operands, ARRAY_SIZE(operands), image_operands_mask, image_operands, image_operand_count);
+}
+
+static void vkd3d_spirv_build_op_image_write(struct vkd3d_spirv_builder *builder,
+        uint32_t image_id, uint32_t coordinate_id, uint32_t texel_id,
+        uint32_t image_operands, const uint32_t *operands, unsigned int operand_count)
+{
+    if (image_operands)
+        FIXME("Image operands not supported.\n");
+
+    vkd3d_spirv_build_op3(&builder->function_stream, SpvOpImageWrite,
+            image_id, coordinate_id, texel_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_array_length(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t struct_id, uint32_t member_id)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpArrayLength, result_type, struct_id, member_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_query_size_lod(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t lod_id)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpImageQuerySizeLod, result_type, image_id, lod_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_query_size(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpImageQuerySize, result_type, image_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_query_levels(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpImageQueryLevels, result_type, image_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_query_samples(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id)
+{
+    return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
+            SpvOpImageQuerySamples, result_type, image_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_image_query_lod(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t image_id, uint32_t coordinate_id)
+{
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpImageQueryLod, result_type, image_id, coordinate_id);
+}
+
+static void vkd3d_spirv_build_op_emit_vertex(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_op(&builder->function_stream, SpvOpEmitVertex);
+}
+
+static void vkd3d_spirv_build_op_end_primitive(struct vkd3d_spirv_builder *builder)
+{
+    return vkd3d_spirv_build_op(&builder->function_stream, SpvOpEndPrimitive);
+}
+
+static void vkd3d_spirv_build_op_control_barrier(struct vkd3d_spirv_builder *builder,
+        uint32_t execution_id, uint32_t memory_id, uint32_t memory_semantics_id)
+{
+    vkd3d_spirv_build_op3(&builder->function_stream,
+            SpvOpControlBarrier, execution_id, memory_id, memory_semantics_id);
+}
+
+static void vkd3d_spirv_build_op_memory_barrier(struct vkd3d_spirv_builder *builder,
+        uint32_t memory_id, uint32_t memory_semantics_id)
+{
+    vkd3d_spirv_build_op2(&builder->function_stream,
+            SpvOpMemoryBarrier, memory_id, memory_semantics_id);
+}
+
+static uint32_t vkd3d_spirv_build_op_glsl_std450_tr1(struct vkd3d_spirv_builder *builder,
+        enum GLSLstd450 op, uint32_t result_type, uint32_t operand)
+{
+    uint32_t id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+    return vkd3d_spirv_build_op_ext_inst(builder, result_type, id, op, &operand, 1);
+}
+
+static uint32_t vkd3d_spirv_build_op_glsl_std450_fabs(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_glsl_std450_tr1(builder, GLSLstd450FAbs, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_glsl_std450_sin(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_glsl_std450_tr1(builder, GLSLstd450Sin, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_glsl_std450_cos(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t operand)
+{
+    return vkd3d_spirv_build_op_glsl_std450_tr1(builder, GLSLstd450Cos, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_glsl_std450_nclamp(struct vkd3d_spirv_builder *builder,
+        uint32_t result_type, uint32_t x, uint32_t min, uint32_t max)
+{
+    uint32_t glsl_std450_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+    uint32_t operands[] = {x, min, max};
+    return vkd3d_spirv_build_op_ext_inst(builder, result_type, glsl_std450_id,
+            GLSLstd450NClamp, operands, ARRAY_SIZE(operands));
+}
+
+static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count)
+{
+    uint32_t scalar_id;
+
+    if (component_count == 1)
+    {
+        switch (component_type)
+        {
+            case VKD3D_SHADER_COMPONENT_VOID:
+                return vkd3d_spirv_get_op_type_void(builder);
+                break;
+            case VKD3D_SHADER_COMPONENT_FLOAT:
+                return vkd3d_spirv_get_op_type_float(builder, 32);
+                break;
+            case VKD3D_SHADER_COMPONENT_INT:
+            case VKD3D_SHADER_COMPONENT_UINT:
+                return vkd3d_spirv_get_op_type_int(builder, 32, component_type == VKD3D_SHADER_COMPONENT_INT);
+                break;
+            case VKD3D_SHADER_COMPONENT_BOOL:
+                return vkd3d_spirv_get_op_type_bool(builder);
+                break;
+            default:
+                FIXME("Unhandled component type %#x.\n", component_type);
+                return 0;
+        }
+    }
+    else
+    {
+        assert(component_type != VKD3D_SHADER_COMPONENT_VOID);
+        scalar_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+        return vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count);
+    }
+}
+
+static void vkd3d_spirv_builder_init(struct vkd3d_spirv_builder *builder, const char *entry_point)
+{
+    vkd3d_spirv_stream_init(&builder->debug_stream);
+    vkd3d_spirv_stream_init(&builder->annotation_stream);
+    vkd3d_spirv_stream_init(&builder->global_stream);
+    vkd3d_spirv_stream_init(&builder->function_stream);
+    vkd3d_spirv_stream_init(&builder->execution_mode_stream);
+
+    vkd3d_spirv_stream_init(&builder->insertion_stream);
+    builder->insertion_location = ~(size_t)0;
+
+    builder->current_id = 1;
+
+    rb_init(&builder->declarations, vkd3d_spirv_declaration_compare);
+
+    builder->main_function_id = vkd3d_spirv_alloc_id(builder);
+    vkd3d_spirv_build_op_name(builder, builder->main_function_id, entry_point);
+}
+
+static void vkd3d_spirv_builder_begin_main_function(struct vkd3d_spirv_builder *builder)
+{
+    uint32_t void_id, function_type_id;
+
+    void_id = vkd3d_spirv_get_op_type_void(builder);
+    function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, NULL, 0);
+
+    vkd3d_spirv_build_op_function(builder, void_id,
+            builder->main_function_id, SpvFunctionControlMaskNone, function_type_id);
+    vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
+    builder->main_function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+}
+
+static void vkd3d_spirv_builder_free(struct vkd3d_spirv_builder *builder)
+{
+    vkd3d_spirv_stream_free(&builder->debug_stream);
+    vkd3d_spirv_stream_free(&builder->annotation_stream);
+    vkd3d_spirv_stream_free(&builder->global_stream);
+    vkd3d_spirv_stream_free(&builder->function_stream);
+    vkd3d_spirv_stream_free(&builder->execution_mode_stream);
+
+    vkd3d_spirv_stream_free(&builder->insertion_stream);
+
+    rb_destroy(&builder->declarations, vkd3d_spirv_declaration_free, NULL);
+
+    vkd3d_free(builder->iface);
+}
+
+static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
+        struct vkd3d_shader_code *spirv, const char *entry_point)
+{
+    uint64_t capability_mask = builder->capability_mask;
+    struct vkd3d_spirv_stream stream;
+    uint32_t *code;
+    unsigned int i;
+    size_t size;
+
+    vkd3d_spirv_stream_init(&stream);
+
+    vkd3d_spirv_build_word(&stream, SpvMagicNumber);
+    vkd3d_spirv_build_word(&stream, VKD3D_SPIRV_VERSION);
+    vkd3d_spirv_build_word(&stream, VKD3D_SPIRV_GENERATOR_MAGIC);
+    vkd3d_spirv_build_word(&stream, builder->current_id); /* bound */
+    vkd3d_spirv_build_word(&stream, 0); /* schema, reserved */
+
+    /* capabilities */
+    for (i = 0; capability_mask; ++i)
+    {
+        if (capability_mask & 1)
+            vkd3d_spirv_build_op_capability(&stream, i);
+        capability_mask >>= 1;
+    }
+    if (builder->capability_draw_parameters)
+        vkd3d_spirv_build_op_capability(&stream, SpvCapabilityDrawParameters);
+    if (builder->capability_demote_to_helper_invocation)
+        vkd3d_spirv_build_op_capability(&stream, SpvCapabilityDemoteToHelperInvocationEXT);
+
+    /* extensions */
+    if (builder->capability_draw_parameters)
+        vkd3d_spirv_build_op_extension(&stream, "SPV_KHR_shader_draw_parameters");
+    if (builder->capability_demote_to_helper_invocation)
+        vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_demote_to_helper_invocation");
+
+    if (builder->ext_instr_set_glsl_450)
+        vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450");
+
+    /* entry point declarations */
+    vkd3d_spirv_build_op_memory_model(&stream, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
+    vkd3d_spirv_build_op_entry_point(&stream, builder->execution_model, builder->main_function_id,
+            entry_point, builder->iface, builder->iface_element_count);
+
+    /* execution mode declarations */
+    if (builder->invocation_count)
+        vkd3d_spirv_build_op_execution_mode(&builder->execution_mode_stream,
+                builder->main_function_id, SpvExecutionModeInvocations, &builder->invocation_count, 1);
+    vkd3d_spirv_stream_append(&stream, &builder->execution_mode_stream);
+
+    vkd3d_spirv_stream_append(&stream, &builder->debug_stream);
+    vkd3d_spirv_stream_append(&stream, &builder->annotation_stream);
+    vkd3d_spirv_stream_append(&stream, &builder->global_stream);
+    vkd3d_spirv_stream_append(&stream, &builder->function_stream);
+
+    if (!(code = vkd3d_calloc(stream.word_count, sizeof(*code))))
+    {
+        vkd3d_spirv_stream_free(&stream);
+        return false;
+    }
+
+    size = stream.word_count * sizeof(*code);
+    memcpy(code, stream.words, size);
+    vkd3d_spirv_stream_free(&stream);
+
+    spirv->code = code;
+    spirv->size = size;
+
+    return true;
+}
+
+static const struct vkd3d_spirv_resource_type
+{
+    enum vkd3d_shader_resource_type resource_type;
+
+    SpvDim dim;
+    uint32_t arrayed;
+    uint32_t ms;
+
+    unsigned int coordinate_component_count;
+    unsigned int offset_component_count;
+
+    SpvCapability capability;
+    SpvCapability uav_capability;
+}
+vkd3d_spirv_resource_type_table[] =
+{
+    {VKD3D_SHADER_RESOURCE_BUFFER,            SpvDimBuffer, 0, 0, 1, 0,
+            SpvCapabilitySampledBuffer, SpvCapabilityImageBuffer},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_1D,        SpvDim1D,     0, 0, 1, 1,
+            SpvCapabilitySampled1D, SpvCapabilityImage1D},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_2DMS,      SpvDim2D,     0, 1, 2, 2},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_2D,        SpvDim2D,     0, 0, 2, 2},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_3D,        SpvDim3D,     0, 0, 3, 3},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_CUBE,      SpvDimCube,   0, 0, 3, 0},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY,   SpvDim1D,     1, 0, 2, 1,
+            SpvCapabilitySampled1D, SpvCapabilityImage1D},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY,   SpvDim2D,     1, 0, 3, 2},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY, SpvDim2D,     1, 1, 3, 2},
+    {VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY, SpvDimCube,   1, 0, 4, 0,
+            SpvCapabilitySampledCubeArray, SpvCapabilityImageCubeArray},
+};
+
+static const struct vkd3d_spirv_resource_type *vkd3d_get_spirv_resource_type(
+        enum vkd3d_shader_resource_type resource_type)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_spirv_resource_type_table); ++i)
+    {
+        const struct vkd3d_spirv_resource_type* current = &vkd3d_spirv_resource_type_table[i];
+
+        if (current->resource_type == resource_type)
+            return current;
+    }
+
+    FIXME("Unhandled resource type %#x.\n", resource_type);
+    return NULL;
+}
+
+struct vkd3d_symbol_register
+{
+    enum vkd3d_shader_register_type type;
+    unsigned int idx;
+};
+
+struct vkd3d_symbol_resource
+{
+    enum vkd3d_shader_register_type type;
+    unsigned int idx;
+};
+
+struct vkd3d_symbol_sampler
+{
+    unsigned int id;
+};
+
+struct vkd3d_symbol_combined_sampler
+{
+    enum vkd3d_shader_register_type resource_type;
+    unsigned int resource_id;
+    unsigned int sampler_space;
+    unsigned int sampler_index;
+};
+
+struct vkd3d_symbol_register_data
+{
+    SpvStorageClass storage_class;
+    uint32_t member_idx;
+    enum vkd3d_shader_component_type component_type;
+    unsigned int write_mask;
+    unsigned int structure_stride;
+    bool is_aggregate; /* An aggregate, i.e. a structure or an array. */
+    bool is_dynamically_indexed; /* If member_idx is a variable ID instead of a constant. */
+};
+
+struct vkd3d_symbol_resource_data
+{
+    unsigned int register_space;
+    unsigned int register_index;
+    enum vkd3d_shader_component_type sampled_type;
+    uint32_t type_id;
+    const struct vkd3d_spirv_resource_type *resource_type_info;
+    unsigned int structure_stride;
+    bool raw;
+    uint32_t uav_counter_id;
+};
+
+struct vkd3d_symbol_sampler_data
+{
+    unsigned int register_space;
+    unsigned int register_index;
+};
+
+struct vkd3d_symbol
+{
+    struct rb_entry entry;
+
+    enum
+    {
+        VKD3D_SYMBOL_REGISTER,
+        VKD3D_SYMBOL_RESOURCE,
+        VKD3D_SYMBOL_SAMPLER,
+        VKD3D_SYMBOL_COMBINED_SAMPLER,
+    } type;
+
+    union
+    {
+        struct vkd3d_symbol_register reg;
+        struct vkd3d_symbol_resource resource;
+        struct vkd3d_symbol_sampler sampler;
+        struct vkd3d_symbol_combined_sampler combined_sampler;
+    } key;
+
+    uint32_t id;
+    union
+    {
+        struct vkd3d_symbol_register_data reg;
+        struct vkd3d_symbol_resource_data resource;
+        struct vkd3d_symbol_sampler_data sampler;
+    } info;
+};
+
+static int vkd3d_symbol_compare(const void *key, const struct rb_entry *entry)
+{
+    const struct vkd3d_symbol *a = key;
+    const struct vkd3d_symbol *b = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry);
+
+    if (a->type != b->type)
+        return a->type - b->type;
+    return memcmp(&a->key, &b->key, sizeof(a->key));
+}
+
+static void vkd3d_symbol_free(struct rb_entry *entry, void *context)
+{
+    struct vkd3d_symbol *s = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+
+    vkd3d_free(s);
+}
+
+static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
+        const struct vkd3d_shader_register *reg)
+{
+    symbol->type = VKD3D_SYMBOL_REGISTER;
+    memset(&symbol->key, 0, sizeof(symbol->key));
+    symbol->key.reg.type = reg->type;
+    if (vkd3d_shader_register_is_input(reg) && reg->idx[1].offset != ~0u)
+        symbol->key.reg.idx = reg->idx[1].offset;
+    else if (reg->type != VKD3DSPR_IMMCONSTBUFFER)
+        symbol->key.reg.idx = reg->idx[0].offset;
+}
+
+static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol,
+        uint32_t val_id, SpvStorageClass storage_class,
+        enum vkd3d_shader_component_type component_type, DWORD write_mask)
+{
+    symbol->id = val_id;
+    symbol->info.reg.storage_class = storage_class;
+    symbol->info.reg.member_idx = 0;
+    symbol->info.reg.component_type = component_type;
+    symbol->info.reg.write_mask = write_mask;
+    symbol->info.reg.structure_stride = 0;
+    symbol->info.reg.is_aggregate = false;
+    symbol->info.reg.is_dynamically_indexed = false;
+}
+
+static void vkd3d_symbol_make_resource(struct vkd3d_symbol *symbol,
+        const struct vkd3d_shader_register *reg)
+{
+    symbol->type = VKD3D_SYMBOL_RESOURCE;
+    memset(&symbol->key, 0, sizeof(symbol->key));
+    symbol->key.resource.type = reg->type;
+    symbol->key.resource.idx = reg->idx[0].offset;
+}
+
+static void vkd3d_symbol_make_sampler(struct vkd3d_symbol *symbol,
+        const struct vkd3d_shader_register *reg)
+{
+    symbol->type = VKD3D_SYMBOL_SAMPLER;
+    memset(&symbol->key, 0, sizeof(symbol->key));
+    symbol->key.sampler.id = reg->idx[0].offset;
+}
+
+static void vkd3d_symbol_make_combined_sampler(struct vkd3d_symbol *symbol,
+        const struct vkd3d_shader_register *resource_reg, unsigned int sampler_space, unsigned int sampler_index)
+{
+    symbol->type = VKD3D_SYMBOL_COMBINED_SAMPLER;
+    memset(&symbol->key, 0, sizeof(symbol->key));
+    symbol->key.combined_sampler.resource_type = resource_reg->type;
+    symbol->key.combined_sampler.resource_id = resource_reg->idx[0].offset;
+    symbol->key.combined_sampler.sampler_space = sampler_space;
+    symbol->key.combined_sampler.sampler_index = sampler_index;
+}
+
+static struct vkd3d_symbol *vkd3d_symbol_dup(const struct vkd3d_symbol *symbol)
+{
+    struct vkd3d_symbol *s;
+
+    if (!(s = vkd3d_malloc(sizeof(*s))))
+        return NULL;
+
+    return memcpy(s, symbol, sizeof(*s));
+}
+
+static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
+{
+    switch (symbol->type)
+    {
+        case VKD3D_SYMBOL_REGISTER:
+            return vkd3d_dbg_sprintf("register %#x, %u",
+                    symbol->key.reg.type, symbol->key.reg.idx);
+        case VKD3D_SYMBOL_RESOURCE:
+            return vkd3d_dbg_sprintf("resource %#x, %u",
+                    symbol->key.resource.type, symbol->key.resource.idx);
+        case VKD3D_SYMBOL_SAMPLER:
+            return vkd3d_dbg_sprintf("sampler %u",
+                    symbol->key.sampler.id);
+        default:
+            return vkd3d_dbg_sprintf("type %#x", symbol->type);
+    }
+}
+
+struct vkd3d_if_cf_info
+{
+    size_t stream_location;
+    unsigned int id;
+    uint32_t merge_block_id;
+    uint32_t else_block_id;
+};
+
+struct vkd3d_loop_cf_info
+{
+    uint32_t header_block_id;
+    uint32_t continue_block_id;
+    uint32_t merge_block_id;
+};
+
+struct vkd3d_switch_cf_info
+{
+    size_t stream_location;
+    unsigned int id;
+    uint32_t selector_id;
+    uint32_t merge_block_id;
+    uint32_t default_block_id;
+    uint32_t *case_blocks;
+    size_t case_blocks_size;
+    unsigned int case_block_count;
+};
+
+struct vkd3d_control_flow_info
+{
+    union
+    {
+        struct vkd3d_if_cf_info if_;
+        struct vkd3d_loop_cf_info loop;
+        struct vkd3d_switch_cf_info switch_;
+    } u;
+
+    enum
+    {
+        VKD3D_BLOCK_IF,
+        VKD3D_BLOCK_LOOP,
+        VKD3D_BLOCK_SWITCH,
+    } current_block;
+    bool inside_block;
+};
+
+struct vkd3d_push_constant_buffer_binding
+{
+    struct vkd3d_shader_register reg;
+    struct vkd3d_shader_push_constant_buffer pc;
+    unsigned int size;
+};
+
+struct vkd3d_shader_phase
+{
+    enum VKD3D_SHADER_INSTRUCTION_HANDLER type;
+    unsigned int idx;
+    unsigned int instance_count;
+    uint32_t function_id;
+    uint32_t instance_id;
+    size_t function_location;
+};
+
+struct vkd3d_shader_spec_constant
+{
+    enum vkd3d_shader_parameter_name name;
+    uint32_t id;
+};
+
+struct vkd3d_hull_shader_variables
+{
+    uint32_t tess_level_outer_id;
+    uint32_t tess_level_inner_id;
+    uint32_t patch_constants_id;
+};
+
+struct vkd3d_dxbc_compiler
+{
+    struct vkd3d_spirv_builder spirv_builder;
+
+    struct vkd3d_shader_message_context *message_context;
+    bool failed;
+
+    bool strip_debug;
+    bool ssbo_uavs;
+
+    struct rb_tree symbol_table;
+    uint32_t temp_id;
+    unsigned int temp_count;
+    struct vkd3d_hull_shader_variables hs;
+    uint32_t sample_positions_id;
+
+    enum vkd3d_shader_type shader_type;
+
+    unsigned int branch_id;
+    unsigned int loop_id;
+    unsigned int switch_id;
+    unsigned int control_flow_depth;
+    struct vkd3d_control_flow_info *control_flow_info;
+    size_t control_flow_info_size;
+
+    struct vkd3d_shader_interface_info shader_interface;
+    struct vkd3d_push_constant_buffer_binding *push_constants;
+    const struct vkd3d_shader_spirv_target_info *spirv_target_info;
+
+    bool after_declarations_section;
+    const struct vkd3d_shader_signature *input_signature;
+    const struct vkd3d_shader_signature *output_signature;
+    const struct vkd3d_shader_signature *patch_constant_signature;
+    const struct vkd3d_shader_transform_feedback_info *xfb_info;
+    struct vkd3d_shader_output_info
+    {
+        uint32_t id;
+        enum vkd3d_shader_component_type component_type;
+        uint32_t array_element_mask;
+    } *output_info;
+    uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
+    uint32_t private_output_variable_array_idx[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
+    uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
+    uint32_t epilogue_function_id;
+
+    uint32_t binding_idx;
+
+    const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
+    unsigned int input_control_point_count;
+    unsigned int output_control_point_count;
+    bool use_vocp;
+
+    unsigned int shader_phase_count;
+    struct vkd3d_shader_phase *shader_phases;
+    size_t shader_phases_size;
+
+    uint32_t current_spec_constant_id;
+    unsigned int spec_constant_count;
+    struct vkd3d_shader_spec_constant *spec_constants;
+    size_t spec_constants_size;
+    enum vkd3d_shader_compile_option_formatting_flags formatting;
+};
+
+static bool is_control_point_phase(const struct vkd3d_shader_phase *phase)
+{
+    return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE;
+}
+
+static void vkd3d_dxbc_compiler_emit_initial_declarations(struct vkd3d_dxbc_compiler *compiler);
+
+static const char *vkd3d_dxbc_compiler_get_entry_point_name(const struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+
+    return info && info->entry_point ? info->entry_point : "main";
+}
+
+struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
+        const struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info,
+        const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info,
+        struct vkd3d_shader_message_context *message_context)
+{
+    const struct vkd3d_shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature;
+    const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature;
+    const struct vkd3d_shader_interface_info *shader_interface;
+    const struct vkd3d_shader_spirv_target_info *target_info;
+    struct vkd3d_dxbc_compiler *compiler;
+    unsigned int max_element_count;
+    unsigned int i;
+
+    if (!(compiler = vkd3d_malloc(sizeof(*compiler))))
+        return NULL;
+
+    memset(compiler, 0, sizeof(*compiler));
+    compiler->message_context = message_context;
+
+    if ((target_info = vkd3d_find_struct(compile_info->next, SPIRV_TARGET_INFO)))
+    {
+        switch (target_info->environment)
+        {
+            case VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5:
+            case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
+                break;
+            default:
+                WARN("Invalid target environment %#x.\n", target_info->environment);
+                vkd3d_free(compiler);
+                return NULL;
+        }
+
+        compiler->spirv_target_info = target_info;
+    }
+
+    max_element_count = max(output_signature->element_count, patch_constant_signature->element_count);
+    if (!(compiler->output_info = vkd3d_calloc(max_element_count, sizeof(*compiler->output_info))))
+    {
+        vkd3d_free(compiler);
+        return NULL;
+    }
+
+    vkd3d_spirv_builder_init(&compiler->spirv_builder, vkd3d_dxbc_compiler_get_entry_point_name(compiler));
+
+    compiler->formatting = VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT
+            | VKD3D_SHADER_COMPILE_OPTION_FORMATTING_HEADER;
+
+    for (i = 0; i < compile_info->option_count; ++i)
+    {
+        const struct vkd3d_shader_compile_option *option = &compile_info->options[i];
+
+        switch (option->name)
+        {
+            case VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG:
+                compiler->strip_debug = !!option->value;
+                break;
+
+            case VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV:
+                if (option->value == VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_TEXEL_BUFFER)
+                    compiler->ssbo_uavs = false;
+                else if (option->value == VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_BUFFER)
+                    compiler->ssbo_uavs = true;
+                else
+                    WARN("Ignoring unrecognised value %#x for option %#x.\n", option->value, option->name);
+                break;
+
+            case VKD3D_SHADER_COMPILE_OPTION_FORMATTING:
+                compiler->formatting = option->value;
+                break;
+
+            default:
+                WARN("Ignoring unrecognised option %#x with value %#x.\n", option->name, option->value);
+                break;
+        }
+    }
+
+    rb_init(&compiler->symbol_table, vkd3d_symbol_compare);
+
+    compiler->shader_type = shader_version->type;
+
+    compiler->input_signature = &shader_desc->input_signature;
+    compiler->output_signature = &shader_desc->output_signature;
+    compiler->patch_constant_signature = &shader_desc->patch_constant_signature;
+
+    if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO)))
+    {
+        compiler->xfb_info = vkd3d_find_struct(compile_info->next, TRANSFORM_FEEDBACK_INFO);
+
+        compiler->shader_interface = *shader_interface;
+        if (shader_interface->push_constant_buffer_count)
+        {
+            if (!(compiler->push_constants = vkd3d_calloc(shader_interface->push_constant_buffer_count,
+                    sizeof(*compiler->push_constants))))
+            {
+                vkd3d_dxbc_compiler_destroy(compiler);
+                return NULL;
+            }
+            for (i = 0; i < shader_interface->push_constant_buffer_count; ++i)
+                compiler->push_constants[i].pc = shader_interface->push_constant_buffers[i];
+        }
+    }
+
+    compiler->scan_descriptor_info = scan_descriptor_info;
+
+    vkd3d_dxbc_compiler_emit_initial_declarations(compiler);
+
+    return compiler;
+}
+
+static bool vkd3d_dxbc_compiler_use_storage_buffer(const struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_symbol_resource_data *resource)
+{
+    return compiler->ssbo_uavs && resource->resource_type_info->resource_type == VKD3D_SHADER_RESOURCE_BUFFER;
+}
+
+static enum vkd3d_shader_spirv_environment vkd3d_dxbc_compiler_get_target_environment(
+        const struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+
+    return info ? info->environment : VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
+}
+
+static bool vkd3d_dxbc_compiler_is_opengl_target(const struct vkd3d_dxbc_compiler *compiler)
+{
+    return vkd3d_dxbc_compiler_get_target_environment(compiler) == VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5;
+}
+
+static bool vkd3d_dxbc_compiler_is_target_extension_supported(const struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_spirv_extension extension)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+    unsigned int i;
+
+    for (i = 0; info && i < info->extension_count; ++i)
+    {
+        if (info->extensions[i] == extension)
+            return true;
+    }
+
+    return false;
+}
+
+static bool vkd3d_dxbc_compiler_check_shader_visibility(const struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_visibility visibility)
+{
+    switch (visibility)
+    {
+        case VKD3D_SHADER_VISIBILITY_ALL:
+            return true;
+        case VKD3D_SHADER_VISIBILITY_VERTEX:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_VERTEX;
+        case VKD3D_SHADER_VISIBILITY_HULL:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_HULL;
+        case VKD3D_SHADER_VISIBILITY_DOMAIN:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN;
+        case VKD3D_SHADER_VISIBILITY_GEOMETRY:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_GEOMETRY;
+        case VKD3D_SHADER_VISIBILITY_PIXEL:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL;
+        case VKD3D_SHADER_VISIBILITY_COMPUTE:
+            return compiler->shader_type == VKD3D_SHADER_TYPE_COMPUTE;
+        default:
+            ERR("Invalid shader visibility %#x.\n", visibility);
+            return false;
+    }
+}
+
+static struct vkd3d_push_constant_buffer_binding *vkd3d_dxbc_compiler_find_push_constant_buffer(
+        const struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_constant_buffer *cb)
+{
+    unsigned int register_space = cb->register_space;
+    unsigned int reg_idx = cb->register_index;
+    unsigned int i;
+
+    for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
+    {
+        struct vkd3d_push_constant_buffer_binding *current = &compiler->push_constants[i];
+
+        if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->pc.shader_visibility))
+            continue;
+
+        if (current->pc.register_space == register_space && current->pc.register_index == reg_idx)
+            return current;
+    }
+
+    return NULL;
+}
+
+static bool vkd3d_dxbc_compiler_has_combined_sampler(const struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_resource *resource, const struct vkd3d_shader_sampler *sampler)
+{
+    const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
+    const struct vkd3d_shader_combined_resource_sampler *combined_sampler;
+    unsigned int i;
+
+    if (!shader_interface->combined_sampler_count)
+        return false;
+
+    if (resource && resource->reg.reg.type == VKD3DSPR_UAV)
+        return false;
+
+    for (i = 0; i < shader_interface->combined_sampler_count; ++i)
+    {
+        combined_sampler = &shader_interface->combined_samplers[i];
+
+        if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, combined_sampler->shader_visibility))
+            continue;
+
+        if ((!resource || (combined_sampler->resource_space == resource->register_space
+                && combined_sampler->resource_index == resource->register_index))
+                && (!sampler || (combined_sampler->sampler_space == sampler->register_space
+                && combined_sampler->sampler_index == sampler->register_index)))
+            return true;
+    }
+
+    return false;
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_dxbc_compiler_error(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_error error, const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    vkd3d_shader_verror(compiler->message_context, error, format, args);
+    va_end(args);
+    compiler->failed = true;
+}
+
+static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
+        struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg, unsigned int register_space,
+        unsigned int reg_idx, enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
+{
+    const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
+    enum vkd3d_shader_descriptor_type descriptor_type;
+    enum vkd3d_shader_binding_flag resource_type_flag;
+    struct vkd3d_shader_descriptor_binding binding;
+    unsigned int i;
+
+    if (reg->type == VKD3DSPR_CONSTBUFFER)
+        descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+    else if (reg->type == VKD3DSPR_RESOURCE)
+        descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+    else if (reg->type == VKD3DSPR_UAV)
+        descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+    else if (reg->type == VKD3DSPR_SAMPLER)
+        descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER;
+    else
+    {
+        FIXME("Unhandled register type %#x.\n", reg->type);
+        vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE,
+                "Encountered invalid/unhandled register type %#x.", reg->type);
+        goto done;
+    }
+
+    resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
+            ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
+
+    if (is_uav_counter)
+    {
+        assert(descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV);
+        for (i = 0; i < shader_interface->uav_counter_count; ++i)
+        {
+            const struct vkd3d_shader_uav_counter_binding *current = &shader_interface->uav_counters[i];
+
+            if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
+                continue;
+
+            if (current->register_space != register_space || current->register_index != reg_idx)
+                continue;
+
+            if (current->offset)
+            {
+                FIXME("Atomic counter offsets are not supported yet.\n");
+                vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
+                        "Descriptor binding for UAV counter %u, space %u has unsupported ‘offset’ %u.",
+                        reg_idx, register_space, current->offset);
+            }
+
+            if (current->binding.count != 1)
+            {
+                FIXME("Descriptor arrays are not supported.\n");
+                vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
+                        "Descriptor binding for UAV counter %u, space %u has unsupported ‘count’ %u.",
+                        reg_idx, register_space, current->binding.count);
+            }
+
+            return current->binding;
+        }
+        if (shader_interface->uav_counter_count)
+        {
+            FIXME("Could not find descriptor binding for UAV counter %u, space %u.\n", reg_idx, register_space);
+            vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
+                    "Could not find descriptor binding for UAV counter %u, space %u.", reg_idx, register_space);
+        }
+    }
+    else
+    {
+        for (i = 0; i < shader_interface->binding_count; ++i)
+        {
+            const struct vkd3d_shader_resource_binding *current = &shader_interface->bindings[i];
+
+            if (!(current->flags & resource_type_flag))
+                continue;
+
+            if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
+                continue;
+
+            if (current->type != descriptor_type || current->register_space != register_space
+                    || current->register_index != reg_idx)
+                continue;
+
+            if (current->binding.count != 1)
+            {
+                FIXME("Descriptor arrays are not supported.\n");
+                vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
+                        "Descriptor binding for type %#x, space %u, register %u, "
+                        "shader type %#x has unsupported ‘count’ %u.",
+                        descriptor_type, register_space, reg_idx, compiler->shader_type, current->binding.count);
+            }
+
+            return current->binding;
+        }
+        if (shader_interface->binding_count)
+        {
+            FIXME("Could not find binding for type %#x, space %u, register %u, shader type %#x.\n",
+                    descriptor_type, register_space, reg_idx, compiler->shader_type);
+            vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
+                    "Could not find descriptor binding for type %#x, space %u, register %u, shader type %#x.",
+                    descriptor_type, register_space, reg_idx, compiler->shader_type);
+        }
+    }
+
+done:
+    binding.set = 0;
+    binding.count = 1;
+    binding.binding = compiler->binding_idx++;
+    return binding;
+}
+
+static void vkd3d_dxbc_compiler_emit_descriptor_binding(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t variable_id, const struct vkd3d_shader_descriptor_binding *binding)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationDescriptorSet, binding->set);
+    vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationBinding, binding->binding);
+}
+
+static void vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t variable_id, const struct vkd3d_shader_register *reg, unsigned int register_space,
+        unsigned int register_index, enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
+{
+    struct vkd3d_shader_descriptor_binding binding;
+
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, register_space,
+            register_index, resource_type, is_uav_counter);
+    vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding);
+}
+
+static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_symbol *symbol)
+{
+    struct vkd3d_symbol *s;
+
+    s = vkd3d_symbol_dup(symbol);
+    if (rb_put(&compiler->symbol_table, s, &s->entry) == -1)
+    {
+        ERR("Failed to insert symbol entry (%s).\n", debug_vkd3d_symbol(symbol));
+        vkd3d_free(s);
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count, const uint32_t *values)
+{
+    uint32_t type_id, scalar_type_id, component_ids[VKD3D_VEC4_SIZE];
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int i;
+
+    assert(0 < component_count && component_count <= VKD3D_VEC4_SIZE);
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+
+    switch (component_type)
+    {
+        case VKD3D_SHADER_COMPONENT_UINT:
+        case VKD3D_SHADER_COMPONENT_INT:
+        case VKD3D_SHADER_COMPONENT_FLOAT:
+            break;
+        default:
+            FIXME("Unhandled component_type %#x.\n", component_type);
+            return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
+    }
+
+    if (component_count == 1)
+    {
+        return vkd3d_spirv_get_op_constant(builder, type_id, *values);
+    }
+    else
+    {
+        scalar_type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+        for (i = 0; i < component_count; ++i)
+            component_ids[i] = vkd3d_spirv_get_op_constant(builder, scalar_type_id, values[i]);
+        return vkd3d_spirv_get_op_constant_composite(builder, type_id, component_ids, component_count);
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_uint(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t value)
+{
+    return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_UINT, 1, &value);
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_float(struct vkd3d_dxbc_compiler *compiler,
+        float value)
+{
+    return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_FLOAT, 1, (uint32_t *)&value);
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_vector(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count, uint32_t value)
+{
+    const uint32_t values[] = {value, value, value, value};
+    return vkd3d_dxbc_compiler_get_constant(compiler, component_type, component_count, values);
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_uint_vector(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t value, unsigned int component_count)
+{
+    return vkd3d_dxbc_compiler_get_constant_vector(compiler, VKD3D_SHADER_COMPONENT_UINT, component_count, value);
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_constant_float_vector(struct vkd3d_dxbc_compiler *compiler,
+        float value, unsigned int component_count)
+{
+    const float values[] = {value, value, value, value};
+    return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_FLOAT,
+            component_count, (const uint32_t *)values);
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_type_id_for_reg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    return vkd3d_spirv_get_type_id(builder,
+            vkd3d_component_type_from_data_type(reg->data_type),
+            vkd3d_write_mask_component_count(write_mask));
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_type_id_for_dst(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst)
+{
+    return vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, &dst->reg, dst->write_mask);
+}
+
+static bool vkd3d_dxbc_compiler_get_register_name(char *buffer, unsigned int buffer_size,
+        const struct vkd3d_shader_register *reg)
+{
+    unsigned int idx;
+
+    idx = reg->idx[1].offset != ~0u ? reg->idx[1].offset : reg->idx[0].offset;
+    switch (reg->type)
+    {
+        case VKD3DSPR_RESOURCE:
+            snprintf(buffer, buffer_size, "t%u", reg->idx[0].offset);
+            break;
+        case VKD3DSPR_UAV:
+            snprintf(buffer, buffer_size, "u%u", reg->idx[0].offset);
+            break;
+        case VKD3DSPR_SAMPLER:
+            snprintf(buffer, buffer_size, "s%u", reg->idx[0].offset);
+            break;
+        case VKD3DSPR_CONSTBUFFER:
+            snprintf(buffer, buffer_size, "cb%u_%u", reg->idx[0].offset, reg->idx[1].offset);
+            break;
+        case VKD3DSPR_INPUT:
+            snprintf(buffer, buffer_size, "v%u", idx);
+            break;
+        case VKD3DSPR_INCONTROLPOINT:
+            snprintf(buffer, buffer_size, "vicp%u", idx);
+            break;
+        case VKD3DSPR_OUTPUT:
+        case VKD3DSPR_COLOROUT:
+            snprintf(buffer, buffer_size, "o%u", idx);
+            break;
+        case VKD3DSPR_DEPTHOUT:
+        case VKD3DSPR_DEPTHOUTGE:
+        case VKD3DSPR_DEPTHOUTLE:
+            snprintf(buffer, buffer_size, "oDepth");
+            break;
+        case VKD3DSPR_FORKINSTID:
+            snprintf(buffer, buffer_size, "vForkInstanceId");
+            break;
+        case VKD3DSPR_JOININSTID:
+            snprintf(buffer, buffer_size, "vJoinInstanceId");
+            break;
+        case VKD3DSPR_GSINSTID:
+            snprintf(buffer, buffer_size, "vGSInstanceID");
+            break;
+        case VKD3DSPR_PATCHCONST:
+            snprintf(buffer, buffer_size, "vpc%u", idx);
+            break;
+        case VKD3DSPR_TESSCOORD:
+            snprintf(buffer, buffer_size, "vDomainLocation");
+            break;
+        case VKD3DSPR_THREADID:
+            snprintf(buffer, buffer_size, "vThreadID");
+            break;
+        case VKD3DSPR_LOCALTHREADID:
+            snprintf(buffer, buffer_size, "vThreadIDInGroup");
+            break;
+        case VKD3DSPR_LOCALTHREADINDEX:
+            snprintf(buffer, buffer_size, "vThreadIDInGroupFlattened");
+            break;
+        case VKD3DSPR_THREADGROUPID:
+            snprintf(buffer, buffer_size, "vThreadGroupID");
+            break;
+        case VKD3DSPR_GROUPSHAREDMEM:
+            snprintf(buffer, buffer_size, "g%u", reg->idx[0].offset);
+            break;
+        case VKD3DSPR_IDXTEMP:
+            snprintf(buffer, buffer_size, "x%u", idx);
+            break;
+        case VKD3DSPR_COVERAGE:
+            snprintf(buffer, buffer_size, "vCoverage");
+            break;
+        case VKD3DSPR_SAMPLEMASK:
+            snprintf(buffer, buffer_size, "oMask");
+            break;
+        case VKD3DSPR_OUTPOINTID:
+        case VKD3DSPR_PRIMID:
+            /* SPIRV-Tools disassembler generates names for SPIR-V built-ins. */
+            return false;
+        default:
+            FIXME("Unhandled register %#x.\n", reg->type);
+            snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type);
+            return false;
+    }
+
+    return true;
+}
+
+static void vkd3d_dxbc_compiler_emit_register_debug_name(struct vkd3d_spirv_builder *builder,
+        uint32_t id, const struct vkd3d_shader_register *reg)
+{
+    char debug_name[256];
+    if (vkd3d_dxbc_compiler_get_register_name(debug_name, ARRAY_SIZE(debug_name), reg))
+        vkd3d_spirv_build_op_name(builder, id, "%s", debug_name);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_variable(struct vkd3d_dxbc_compiler *compiler,
+        struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id;
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+    return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_array_variable(struct vkd3d_dxbc_compiler *compiler,
+        struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count, unsigned int array_length)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, length_id, ptr_type_id;
+
+    if (!array_length)
+        return vkd3d_dxbc_compiler_emit_variable(compiler,
+                stream, storage_class, component_type, component_count);
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+    length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, array_length);
+    type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+    return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
+}
+
+static const struct vkd3d_shader_parameter *vkd3d_dxbc_compiler_get_shader_parameter(
+        struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+    unsigned int i;
+
+    for (i = 0; info && i < info->parameter_count; ++i)
+    {
+        if (info->parameters[i].name == name)
+            return &info->parameters[i];
+    }
+
+    return NULL;
+}
+
+static const struct vkd3d_spec_constant_info
+{
+    enum vkd3d_shader_parameter_name name;
+    uint32_t default_value;
+    const char *debug_name;
+}
+vkd3d_shader_parameters[] =
+{
+    {VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, 1, "sample_count"},
+};
+
+static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_shader_parameter_name name)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_shader_parameters); ++i)
+    {
+        if (vkd3d_shader_parameters[i].name == name)
+            return &vkd3d_shader_parameters[i];
+    }
+
+    FIXME("Unhandled parameter name %#x.\n", name);
+    return NULL;
+}
+
+static uint32_t vkd3d_dxbc_compiler_alloc_spec_constant_id(struct vkd3d_dxbc_compiler *compiler)
+{
+    if (!compiler->current_spec_constant_id)
+    {
+        const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+        unsigned int i, id = 0;
+
+        for (i = 0; info && i < info->parameter_count; ++i)
+        {
+            const struct vkd3d_shader_parameter *current = &info->parameters[i];
+
+            if (current->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT)
+                id = max(current->u.specialization_constant.id + 1, id);
+        }
+
+        compiler->current_spec_constant_id = id;
+    }
+
+    return compiler->current_spec_constant_id++;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_spec_constant(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_parameter_name name, uint32_t spec_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_spec_constant_info *info;
+    uint32_t type_id, id, default_value;
+
+    info = get_spec_constant_info(name);
+    default_value = info ? info->default_value : 0;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    id = vkd3d_spirv_build_op_spec_constant(builder, type_id, default_value);
+    vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationSpecId, spec_id);
+
+    if (info)
+        vkd3d_spirv_build_op_name(builder, id, "%s", info->debug_name);
+
+    if (vkd3d_array_reserve((void **)&compiler->spec_constants, &compiler->spec_constants_size,
+            compiler->spec_constant_count + 1, sizeof(*compiler->spec_constants)))
+    {
+        struct vkd3d_shader_spec_constant *constant = &compiler->spec_constants[compiler->spec_constant_count++];
+        constant->name = name;
+        constant->id = id;
+    }
+
+    return id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_spec_constant(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_parameter_name name, uint32_t spec_id)
+{
+    unsigned int i;
+
+    for (i = 0; i < compiler->spec_constant_count; ++i)
+    {
+        if (compiler->spec_constants[i].name == name)
+            return compiler->spec_constants[i].id;
+    }
+
+    return vkd3d_dxbc_compiler_emit_spec_constant(compiler, name, spec_id);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_uint_shader_parameter(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_parameter_name name)
+{
+    const struct vkd3d_shader_parameter *parameter;
+
+    if (!(parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, name)))
+    {
+        WARN("Unresolved shader parameter %#x.\n", name);
+        goto default_parameter;
+    }
+
+    if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
+        return vkd3d_dxbc_compiler_get_constant_uint(compiler, parameter->u.immediate_constant.u.u32);
+    if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT)
+        return vkd3d_dxbc_compiler_get_spec_constant(compiler, name, parameter->u.specialization_constant.id);
+
+    FIXME("Unhandled parameter type %#x.\n", parameter->type);
+
+default_parameter:
+    return vkd3d_dxbc_compiler_get_spec_constant(compiler,
+            name, vkd3d_dxbc_compiler_alloc_spec_constant_id(compiler));
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_construct_vector(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count,
+        uint32_t val_id, unsigned int val_component_idx, unsigned int val_component_count)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    uint32_t type_id, result_id;
+    unsigned int i;
+
+    assert(val_component_idx < val_component_count);
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+    if (val_component_count == 1)
+    {
+        for (i = 0; i < component_count; ++i)
+            components[i] = val_id;
+        result_id = vkd3d_spirv_build_op_composite_construct(builder,
+                type_id, components, component_count);
+    }
+    else
+    {
+        for (i = 0; i < component_count; ++i)
+            components[i] = val_component_idx;
+        result_id = vkd3d_spirv_build_op_vector_shuffle(builder,
+                type_id, val_id, val_id, components, component_count);
+    }
+    return result_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_src_param *src, DWORD write_mask);
+
+static uint32_t vkd3d_dxbc_compiler_emit_register_addressing(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register_index *reg_index)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, addr_id;
+
+    if (!reg_index->rel_addr)
+        return vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset);
+
+    addr_id = vkd3d_dxbc_compiler_emit_load_src(compiler, reg_index->rel_addr, VKD3DSP_WRITEMASK_0);
+    if (reg_index->offset)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        addr_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                addr_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset));
+    }
+    return addr_id;
+}
+
+struct vkd3d_shader_register_info
+{
+    uint32_t id;
+    SpvStorageClass storage_class;
+    enum vkd3d_shader_component_type component_type;
+    unsigned int write_mask;
+    uint32_t member_idx;
+    unsigned int structure_stride;
+    bool is_aggregate;
+    bool is_dynamically_indexed;
+};
+
+static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info)
+{
+    struct vkd3d_symbol reg_symbol, *symbol;
+    struct rb_entry *entry;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+
+    if (reg->type == VKD3DSPR_TEMP)
+    {
+        assert(reg->idx[0].offset < compiler->temp_count);
+        register_info->id = compiler->temp_id + reg->idx[0].offset;
+        register_info->storage_class = SpvStorageClassFunction;
+        register_info->member_idx = 0;
+        register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
+        register_info->write_mask = VKD3DSP_WRITEMASK_ALL;
+        register_info->structure_stride = 0;
+        register_info->is_aggregate = false;
+        register_info->is_dynamically_indexed = false;
+        return true;
+    }
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    if (!(entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+    {
+        FIXME("Unrecognized register (%s).\n", debug_vkd3d_symbol(&reg_symbol));
+        memset(register_info, 0, sizeof(*register_info));
+        return false;
+    }
+
+    symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+    register_info->id = symbol->id;
+    register_info->storage_class = symbol->info.reg.storage_class;
+    register_info->member_idx = symbol->info.reg.member_idx;
+    register_info->component_type = symbol->info.reg.component_type;
+    register_info->write_mask = symbol->info.reg.write_mask;
+    register_info->structure_stride = symbol->info.reg.structure_stride;
+    register_info->is_aggregate = symbol->info.reg.is_aggregate;
+    register_info->is_dynamically_indexed = symbol->info.reg.is_dynamically_indexed;
+
+    return true;
+}
+
+static bool register_is_descriptor(const struct vkd3d_shader_register *reg)
+{
+    switch (reg->type)
+    {
+        case VKD3DSPR_SAMPLER:
+        case VKD3DSPR_RESOURCE:
+        case VKD3DSPR_CONSTBUFFER:
+        case VKD3DSPR_UAV:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int component_count, index_count = 0;
+    uint32_t type_id, ptr_type_id;
+    uint32_t indexes[2];
+
+    if (reg->type == VKD3DSPR_CONSTBUFFER)
+    {
+        assert(!reg->idx[0].rel_addr);
+        indexes[index_count++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, register_info->member_idx);
+        indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg->idx[2]);
+    }
+    else if (reg->type == VKD3DSPR_IMMCONSTBUFFER)
+    {
+        indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg->idx[0]);
+    }
+    else if (reg->type == VKD3DSPR_IDXTEMP)
+    {
+        indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg->idx[1]);
+    }
+    else if (register_info->is_aggregate)
+    {
+        struct vkd3d_shader_register_index reg_idx = reg->idx[0];
+
+        if (reg->idx[1].rel_addr)
+            FIXME("Relative addressing not implemented.\n");
+
+        if (register_info->is_dynamically_indexed)
+        {
+            indexes[index_count++] = vkd3d_spirv_build_op_load(builder,
+                    vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1),
+                    register_info->member_idx, SpvMemoryAccessMaskNone);
+        }
+        else
+        {
+            reg_idx.offset = register_info->member_idx;
+            indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg_idx);
+        }
+    }
+    else
+    {
+        if (reg->idx[1].rel_addr || (reg->idx[1].offset == ~0u && reg->idx[0].rel_addr))
+            FIXME("Relative addressing not implemented.\n");
+
+        /* Handle arrayed registers, e.g. v[3][0]. */
+        if (reg->idx[1].offset != ~0u && !register_is_descriptor(reg))
+            indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg->idx[0]);
+    }
+
+    if (index_count)
+    {
+        component_count = vkd3d_write_mask_component_count(register_info->write_mask);
+        type_id = vkd3d_spirv_get_type_id(builder, register_info->component_type, component_count);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id);
+        register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
+                register_info->id, indexes, index_count);
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_register_id(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_register_info register_info;
+
+    if (vkd3d_dxbc_compiler_get_register_info(compiler, reg, &register_info))
+    {
+        vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, &register_info);
+        return register_info.id;
+    }
+
+    return vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
+            SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+}
+
+static bool vkd3d_swizzle_is_equal(unsigned int dst_write_mask,
+        unsigned int swizzle, unsigned int write_mask)
+{
+    return vkd3d_compact_swizzle(VKD3D_SHADER_NO_SWIZZLE, dst_write_mask) == vkd3d_compact_swizzle(swizzle, write_mask);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_swizzle(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t val_id, unsigned int val_write_mask, enum vkd3d_shader_component_type component_type,
+        unsigned int swizzle, unsigned int write_mask)
+{
+    unsigned int i, component_idx, component_count, val_component_count;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, components[VKD3D_VEC4_SIZE];
+
+    component_count = vkd3d_write_mask_component_count(write_mask);
+    val_component_count = vkd3d_write_mask_component_count(val_write_mask);
+
+    if (component_count == val_component_count
+            && (component_count == 1 || vkd3d_swizzle_is_equal(val_write_mask, swizzle, write_mask)))
+        return val_id;
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+
+    if (component_count == 1)
+    {
+        component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+        component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
+        component_idx -= vkd3d_write_mask_get_component_idx(val_write_mask);
+        return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx);
+    }
+
+    if (val_component_count == 1)
+    {
+        for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
+        {
+            if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            {
+                assert(VKD3DSP_WRITEMASK_0 << vkd3d_swizzle_get_component(swizzle, i) == val_write_mask);
+                components[component_idx++] = val_id;
+            }
+        }
+        return vkd3d_spirv_build_op_composite_construct(builder, type_id, components, component_count);
+    }
+
+    for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            components[component_idx++] = vkd3d_swizzle_get_component(swizzle, i);
+    }
+    return vkd3d_spirv_build_op_vector_shuffle(builder,
+            type_id, val_id, val_id, components, component_count);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_vector_shuffle(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t vector1_id, uint32_t vector2_id, unsigned int swizzle, unsigned int write_mask,
+        enum vkd3d_shader_component_type component_type, unsigned int component_count)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    uint32_t type_id;
+    unsigned int i;
+
+    assert(component_count <= ARRAY_SIZE(components));
+
+    for (i = 0; i < component_count; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            components[i] = vkd3d_swizzle_get_component(swizzle, i);
+        else
+            components[i] = VKD3D_VEC4_SIZE + vkd3d_swizzle_get_component(swizzle, i);
+    }
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+    return vkd3d_spirv_build_op_vector_shuffle(builder,
+            type_id, vector1_id, vector2_id, components, component_count);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_constant(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+    uint32_t values[VKD3D_VEC4_SIZE] = {0};
+    unsigned int i, j;
+
+    assert(reg->type == VKD3DSPR_IMMCONST);
+
+    if (reg->immconst_type == VKD3D_IMMCONST_SCALAR)
+    {
+        for (i = 0; i < component_count; ++i)
+            values[i] = *reg->u.immconst_uint;
+    }
+    else
+    {
+        for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+        {
+            if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+                values[j++] = reg->u.immconst_uint[vkd3d_swizzle_get_component(swizzle, i)];
+        }
+    }
+
+    return vkd3d_dxbc_compiler_get_constant(compiler,
+            vkd3d_component_type_from_data_type(reg->data_type), component_count, values);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_scalar(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask,
+        const struct vkd3d_shader_register_info *reg_info)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id, index, reg_id, val_id;
+    unsigned int component_idx, reg_component_count;
+    enum vkd3d_shader_component_type component_type;
+    unsigned int skipped_component_mask;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+    assert(vkd3d_write_mask_component_count(write_mask) == 1);
+
+    component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+    component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
+    skipped_component_mask = ~reg_info->write_mask & ((VKD3DSP_WRITEMASK_0 << component_idx) - 1);
+    if (skipped_component_mask)
+        component_idx -= vkd3d_write_mask_component_count(skipped_component_mask);
+    component_type = vkd3d_component_type_from_data_type(reg->data_type);
+
+    reg_component_count = vkd3d_write_mask_component_count(reg_info->write_mask);
+
+    if (component_idx >= vkd3d_write_mask_component_count(reg_info->write_mask))
+    {
+        ERR("Invalid component_idx %u for register %#x, %u (write_mask %#x).\n",
+                component_idx, reg->type, reg->idx[0].offset, reg_info->write_mask);
+    }
+
+    type_id = vkd3d_spirv_get_type_id(builder, reg_info->component_type, 1);
+    reg_id = reg_info->id;
+    if (reg_component_count != 1)
+    {
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info->storage_class, type_id);
+        index = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
+        reg_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, reg_id, index);
+    }
+
+    val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_id, SpvMemoryAccessMaskNone);
+
+    if (component_type != reg_info->component_type)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    return val_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_reg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    enum vkd3d_shader_component_type component_type;
+    struct vkd3d_shader_register_info reg_info;
+    unsigned int component_count;
+    uint32_t type_id, val_id;
+
+    if (reg->type == VKD3DSPR_IMMCONST)
+        return vkd3d_dxbc_compiler_emit_load_constant(compiler, reg, swizzle, write_mask);
+
+    component_count = vkd3d_write_mask_component_count(write_mask);
+    component_type = vkd3d_component_type_from_data_type(reg->data_type);
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, reg, &reg_info))
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+        return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
+    }
+    vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, &reg_info);
+
+    /* Intermediate value (no storage class). */
+    if (reg_info.storage_class == SpvStorageClassMax)
+    {
+        val_id = reg_info.id;
+    }
+    else if (component_count == 1)
+    {
+        return vkd3d_dxbc_compiler_emit_load_scalar(compiler, reg, swizzle, write_mask, &reg_info);
+    }
+    else
+    {
+        type_id = vkd3d_spirv_get_type_id(builder,
+                reg_info.component_type, vkd3d_write_mask_component_count(reg_info.write_mask));
+        val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_info.id, SpvMemoryAccessMaskNone);
+    }
+
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler,
+            val_id, reg_info.write_mask, reg_info.component_type, swizzle, write_mask);
+
+    if (component_type != reg_info.component_type)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    return val_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_execution_mode(struct vkd3d_dxbc_compiler *compiler,
+        SpvExecutionMode mode, const uint32_t *literals, unsigned int literal_count)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    vkd3d_spirv_build_op_execution_mode(&builder->execution_mode_stream,
+            builder->main_function_id, mode, literals, literal_count);
+}
+
+static void vkd3d_dxbc_compiler_emit_execution_mode1(struct vkd3d_dxbc_compiler *compiler,
+        SpvExecutionMode mode, const uint32_t literal)
+{
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, &literal, 1);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_abs(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id;
+
+    if (reg->data_type == VKD3D_DATA_FLOAT)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
+        return vkd3d_spirv_build_op_glsl_std450_fabs(builder, type_id, val_id);
+    }
+
+    FIXME("Unhandled data type %#x.\n", reg->data_type);
+    return val_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_neg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id;
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, reg, write_mask);
+    if (reg->data_type == VKD3D_DATA_FLOAT)
+        return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id);
+    else if (reg->data_type == VKD3D_DATA_INT)
+        return vkd3d_spirv_build_op_snegate(builder, type_id, val_id);
+
+    FIXME("Unhandled data type %#x.\n", reg->data_type);
+    return val_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_src_modifier(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask,
+        enum vkd3d_shader_src_modifier modifier, uint32_t val_id)
+{
+    switch (modifier)
+    {
+        case VKD3DSPSM_NONE:
+            break;
+        case VKD3DSPSM_NEG:
+            return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
+        case VKD3DSPSM_ABS:
+            return vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
+        case VKD3DSPSM_ABSNEG:
+            val_id = vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
+            return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
+        default:
+            FIXME("Unhandled src modifier %#x.\n", modifier);
+            break;
+    }
+
+    return val_id;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_src_param *src, DWORD write_mask)
+{
+    uint32_t val_id;
+
+    val_id = vkd3d_dxbc_compiler_emit_load_reg(compiler, &src->reg, src->swizzle, write_mask);
+    return vkd3d_dxbc_compiler_emit_src_modifier(compiler, &src->reg, write_mask, src->modifiers, val_id);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_src_with_type(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_src_param *src, DWORD write_mask, enum vkd3d_shader_component_type component_type)
+{
+    struct vkd3d_shader_src_param src_param = *src;
+
+    src_param.reg.data_type = vkd3d_data_type_from_component_type(component_type);
+    return vkd3d_dxbc_compiler_emit_load_src(compiler, &src_param, write_mask);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_scalar(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_shader_component_type component_type,
+        SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, ptr_type_id, index;
+    unsigned int component_idx;
+
+    if (vkd3d_write_mask_component_count(dst_write_mask) > 1)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+        component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+        component_idx -= vkd3d_write_mask_get_component_idx(dst_write_mask);
+        index = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
+        dst_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, dst_id, index);
+    }
+
+    vkd3d_spirv_build_op_store(builder, dst_id, val_id, SpvMemoryAccessMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_store(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_shader_component_type component_type,
+        SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int component_count, dst_component_count;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    unsigned int i, src_idx, dst_idx;
+    uint32_t type_id, dst_val_id;
+
+    assert(write_mask);
+
+    component_count = vkd3d_write_mask_component_count(write_mask);
+    dst_component_count = vkd3d_write_mask_component_count(dst_write_mask);
+
+    if (dst_component_count == 1 && component_count != 1)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+        val_id = vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id,
+                vkd3d_write_mask_get_component_idx(dst_write_mask));
+        write_mask &= dst_write_mask;
+        component_count = 1;
+    }
+
+    if (component_count == 1)
+    {
+        return vkd3d_dxbc_compiler_emit_store_scalar(compiler,
+                dst_id, dst_write_mask, component_type, storage_class, write_mask, val_id);
+    }
+
+    if (dst_component_count != component_count)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, dst_component_count);
+        dst_val_id = vkd3d_spirv_build_op_load(builder, type_id, dst_id, SpvMemoryAccessMaskNone);
+
+        assert(component_count <= ARRAY_SIZE(components));
+
+        for (i = 0, src_idx = 0, dst_idx = 0; dst_idx < VKD3D_VEC4_SIZE; ++dst_idx)
+        {
+            if (write_mask & (VKD3DSP_WRITEMASK_0 << dst_idx))
+                components[i] = dst_component_count + src_idx++;
+            else
+                components[i] = i;
+
+            if (dst_write_mask & (VKD3DSP_WRITEMASK_0 << dst_idx))
+                ++i;
+        }
+
+        val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
+                type_id, dst_val_id, val_id, components, dst_component_count);
+    }
+
+    vkd3d_spirv_build_op_store(builder, dst_id, val_id, SpvMemoryAccessMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_reg(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, unsigned int write_mask, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    enum vkd3d_shader_component_type component_type;
+    struct vkd3d_shader_register_info reg_info;
+    uint32_t type_id;
+
+    assert(reg->type != VKD3DSPR_IMMCONST);
+
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, reg, &reg_info))
+        return;
+    vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, &reg_info);
+
+    component_type = vkd3d_component_type_from_data_type(reg->data_type);
+    if (component_type != reg_info.component_type)
+    {
+        unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+        type_id = vkd3d_spirv_get_type_id(builder, reg_info.component_type, component_count);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+        component_type = reg_info.component_type;
+    }
+
+    vkd3d_dxbc_compiler_emit_store(compiler,
+            reg_info.id, reg_info.write_mask, component_type, reg_info.storage_class, write_mask, val_id);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_sat(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, zero_id, one_id;
+
+    zero_id = vkd3d_dxbc_compiler_get_constant_float_vector(compiler, 0.0f, component_count);
+    one_id = vkd3d_dxbc_compiler_get_constant_float_vector(compiler, 1.0f, component_count);
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, reg, write_mask);
+    if (reg->data_type == VKD3D_DATA_FLOAT)
+        return vkd3d_spirv_build_op_glsl_std450_nclamp(builder, type_id, val_id, zero_id, one_id);
+
+    FIXME("Unhandled data type %#x.\n", reg->data_type);
+    return val_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_store_dst(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, uint32_t val_id)
+{
+    assert(!(dst->modifiers & ~VKD3DSPDM_SATURATE));
+    if (dst->modifiers & VKD3DSPDM_SATURATE)
+        val_id = vkd3d_dxbc_compiler_emit_sat(compiler, &dst->reg, dst->write_mask, val_id);
+
+    vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_dst_swizzled(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, uint32_t val_id,
+        enum vkd3d_shader_component_type component_type, DWORD swizzle)
+{
+    struct vkd3d_shader_dst_param typed_dst = *dst;
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler,
+            val_id, VKD3DSP_WRITEMASK_ALL, component_type, swizzle, dst->write_mask);
+    /* XXX: The register data type could be fixed by the shader parser. For SM5
+     * shaders the data types are stored in instructions modifiers.
+     */
+    typed_dst.reg.data_type = vkd3d_data_type_from_component_type(component_type);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, &typed_dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_dst_components(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_component_type component_type,
+        uint32_t *component_ids)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, val_id;
+
+    if (component_count > 1)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+        val_id = vkd3d_spirv_build_op_composite_construct(builder,
+                type_id, component_ids, component_count);
+    }
+    else
+    {
+        val_id = *component_ids;
+    }
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_store_dst_scalar(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, uint32_t val_id,
+        enum vkd3d_shader_component_type component_type, DWORD swizzle)
+{
+    unsigned int component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    uint32_t component_ids[VKD3D_VEC4_SIZE];
+    unsigned int component_idx, i;
+
+    component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
+    for (i = 0; i < component_count; ++i)
+    {
+        if (vkd3d_swizzle_get_component(swizzle, component_idx + i))
+            ERR("Invalid swizzle %#x for scalar value, write mask %#x.\n", swizzle, dst->write_mask);
+
+        component_ids[i] = val_id;
+    }
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler, dst, component_type, component_ids);
+}
+
+static void vkd3d_dxbc_compiler_decorate_builtin(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t target_id, SpvBuiltIn builtin)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    switch (builtin)
+    {
+        case SpvBuiltInPrimitiveId:
+            if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL)
+                vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
+            break;
+        case SpvBuiltInFragDepth:
+            vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthReplacing, NULL, 0);
+            break;
+        case SpvBuiltInLayer:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
+            break;
+        case SpvBuiltInViewportIndex:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityMultiViewport);
+            break;
+        case SpvBuiltInSampleId:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading);
+            break;
+        case SpvBuiltInClipDistance:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityClipDistance);
+            break;
+        case SpvBuiltInCullDistance:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilityCullDistance);
+            break;
+        default:
+            break;
+    }
+
+    vkd3d_spirv_build_op_decorate1(builder, target_id, SpvDecorationBuiltIn, builtin);
+}
+
+static void vkd3d_dxbc_compiler_emit_interpolation_decorations(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t id, enum vkd3d_shader_interpolation_mode mode)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    switch (mode)
+    {
+        case VKD3DSIM_NONE:
+            break;
+        case VKD3DSIM_CONSTANT:
+            vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationFlat, NULL, 0);
+            break;
+        case VKD3DSIM_LINEAR:
+            break;
+        case VKD3DSIM_LINEAR_CENTROID:
+            vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationCentroid, NULL, 0);
+            break;
+        case VKD3DSIM_LINEAR_NOPERSPECTIVE:
+            vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationNoPerspective, NULL, 0);
+            break;
+        case VKD3DSIM_LINEAR_SAMPLE:
+            vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading);
+            vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationSample, NULL, 0);
+            break;
+        default:
+            FIXME("Unhandled interpolation mode %#x.\n", mode);
+            break;
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_int_to_bool(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_conditional_op condition, unsigned int component_count, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id;
+    SpvOp op;
+
+    assert(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z)));
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count);
+    op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual;
+    return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, val_id,
+            vkd3d_dxbc_compiler_get_constant_uint_vector(compiler, 0, component_count));
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_bool_to_int(struct vkd3d_dxbc_compiler *compiler,
+        unsigned int component_count, uint32_t val_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, true_id, false_id;
+
+    true_id = vkd3d_dxbc_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count);
+    false_id = vkd3d_dxbc_compiler_get_constant_uint_vector(compiler, 0, component_count);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count);
+    return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+}
+
+typedef uint32_t (*vkd3d_spirv_builtin_fixup_pfn)(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t val_id);
+
+static uint32_t vkd3d_dxbc_compiler_emit_draw_parameter_fixup(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t index_id, SpvBuiltIn base)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t base_var_id, base_id, type_id;
+
+    vkd3d_spirv_enable_capability(builder, SpvCapabilityDrawParameters);
+
+    base_var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
+            SpvStorageClassInput, VKD3D_SHADER_COMPONENT_INT, 1);
+    vkd3d_spirv_add_iface_variable(builder, base_var_id);
+    vkd3d_dxbc_compiler_decorate_builtin(compiler, base_var_id, base);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1);
+    base_id = vkd3d_spirv_build_op_load(builder,
+            type_id, base_var_id, SpvMemoryAccessMaskNone);
+
+    return vkd3d_spirv_build_op_isub(builder, type_id, index_id, base_id);
+}
+
+/* Substitute "VertexIndex - BaseVertex" for SV_VertexID. */
+static uint32_t sv_vertex_id_fixup(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t vertex_index_id)
+{
+    return vkd3d_dxbc_compiler_emit_draw_parameter_fixup(compiler,
+            vertex_index_id, SpvBuiltInBaseVertex);
+}
+
+/* Substitute "InstanceIndex - BaseInstance" for SV_InstanceID. */
+static uint32_t sv_instance_id_fixup(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t instance_index_id)
+{
+    return vkd3d_dxbc_compiler_emit_draw_parameter_fixup(compiler,
+            instance_index_id, SpvBuiltInBaseInstance);
+}
+
+static uint32_t sv_front_face_fixup(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t front_facing_id)
+{
+    return vkd3d_dxbc_compiler_emit_bool_to_int(compiler, 1, front_facing_id);
+}
+
+/* frag_coord.w = 1.0f / frag_coord.w */
+static uint32_t frag_coord_fixup(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t frag_coord_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, w_id;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 1);
+    w_id = vkd3d_spirv_build_op_composite_extract1(builder, type_id, frag_coord_id, 3);
+    w_id = vkd3d_spirv_build_op_fdiv(builder, type_id,
+            vkd3d_dxbc_compiler_get_constant_float(compiler, 1.0f), w_id);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    return vkd3d_spirv_build_op_composite_insert1(builder, type_id, w_id, frag_coord_id, 3);
+}
+
+struct vkd3d_spirv_builtin
+{
+    enum vkd3d_shader_component_type component_type;
+    unsigned int component_count;
+    SpvBuiltIn spirv_builtin;
+    vkd3d_spirv_builtin_fixup_pfn fixup_pfn;
+    unsigned int spirv_array_size;
+    unsigned int member_idx;
+};
+
+/*
+ * The following tables are based on the "14.6. Built-In Variables" section
+ * from the Vulkan spec.
+ */
+static const struct
+{
+    enum vkd3d_shader_input_sysval_semantic sysval;
+    struct vkd3d_spirv_builtin builtin;
+    enum vkd3d_shader_spirv_environment environment;
+}
+vkd3d_system_value_builtins[] =
+{
+    {VKD3D_SIV_VERTEX_ID,   {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInVertexId},
+            VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5},
+    {VKD3D_SIV_INSTANCE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInstanceId},
+            VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5},
+
+    {VKD3D_SIV_POSITION,    {VKD3D_SHADER_COMPONENT_FLOAT, 4, SpvBuiltInPosition}},
+    {VKD3D_SIV_VERTEX_ID,   {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInVertexIndex, sv_vertex_id_fixup}},
+    {VKD3D_SIV_INSTANCE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInstanceIndex, sv_instance_id_fixup}},
+
+    {VKD3D_SIV_PRIMITIVE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInPrimitiveId}},
+
+    {VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInLayer}},
+    {VKD3D_SIV_VIEWPORT_ARRAY_INDEX,      {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInViewportIndex}},
+
+    {VKD3D_SIV_IS_FRONT_FACE, {VKD3D_SHADER_COMPONENT_BOOL, 1, SpvBuiltInFrontFacing, sv_front_face_fixup}},
+
+    {VKD3D_SIV_SAMPLE_INDEX, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleId}},
+
+    {VKD3D_SIV_CLIP_DISTANCE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInClipDistance, NULL, 1}},
+    {VKD3D_SIV_CULL_DISTANCE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInCullDistance, NULL, 1}},
+
+    {VKD3D_SIV_QUAD_U0_TESS_FACTOR,      {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
+    {VKD3D_SIV_QUAD_V0_TESS_FACTOR,      {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
+    {VKD3D_SIV_QUAD_U1_TESS_FACTOR,      {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 2}},
+    {VKD3D_SIV_QUAD_V1_TESS_FACTOR,      {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 3}},
+    {VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 0}},
+    {VKD3D_SIV_QUAD_V_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 1}},
+
+    {VKD3D_SIV_TRIANGLE_U_TESS_FACTOR,     {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
+    {VKD3D_SIV_TRIANGLE_V_TESS_FACTOR,     {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
+    {VKD3D_SIV_TRIANGLE_W_TESS_FACTOR,     {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 2}},
+    {VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 0}},
+
+    {VKD3D_SIV_LINE_DETAIL_TESS_FACTOR,  {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
+    {VKD3D_SIV_LINE_DENSITY_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
+};
+static const struct vkd3d_spirv_builtin vkd3d_pixel_shader_position_builtin =
+{
+    VKD3D_SHADER_COMPONENT_FLOAT, 4, SpvBuiltInFragCoord, frag_coord_fixup,
+};
+static const struct
+{
+    enum vkd3d_shader_register_type reg_type;
+    struct vkd3d_spirv_builtin builtin;
+}
+vkd3d_register_builtins[] =
+{
+    {VKD3DSPR_THREADID,         {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInGlobalInvocationId}},
+    {VKD3DSPR_LOCALTHREADID,    {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInLocalInvocationId}},
+    {VKD3DSPR_LOCALTHREADINDEX, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInLocalInvocationIndex}},
+    {VKD3DSPR_THREADGROUPID,    {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInWorkgroupId}},
+
+    {VKD3DSPR_GSINSTID,         {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInvocationId}},
+    {VKD3DSPR_OUTPOINTID,       {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInvocationId}},
+
+    {VKD3DSPR_PRIMID,           {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInPrimitiveId}},
+
+    {VKD3DSPR_TESSCOORD,        {VKD3D_SHADER_COMPONENT_FLOAT, 3, SpvBuiltInTessCoord}},
+
+    {VKD3DSPR_COVERAGE,         {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
+    {VKD3DSPR_SAMPLEMASK,       {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
+
+    {VKD3DSPR_DEPTHOUT,         {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
+    {VKD3DSPR_DEPTHOUTGE,       {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
+    {VKD3DSPR_DEPTHOUTLE,       {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
+};
+
+static void vkd3d_dxbc_compiler_emit_register_execution_mode(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg)
+{
+    switch (reg->type)
+    {
+        case VKD3DSPR_DEPTHOUTGE:
+            vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthGreater, NULL, 0);
+            break;
+        case VKD3DSPR_DEPTHOUTLE:
+            vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthLess, NULL, 0);
+            break;
+        default:
+            return;
+    }
+}
+
+static const struct vkd3d_spirv_builtin *get_spirv_builtin_for_sysval(
+        const struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_input_sysval_semantic sysval)
+{
+    enum vkd3d_shader_spirv_environment environment;
+    unsigned int i;
+
+    if (!sysval)
+        return NULL;
+
+    /* In pixel shaders, SV_Position is mapped to SpvBuiltInFragCoord. */
+    if (sysval == VKD3D_SIV_POSITION && compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL)
+        return &vkd3d_pixel_shader_position_builtin;
+
+    environment = vkd3d_dxbc_compiler_get_target_environment(compiler);
+    for (i = 0; i < ARRAY_SIZE(vkd3d_system_value_builtins); ++i)
+    {
+        if (vkd3d_system_value_builtins[i].sysval == sysval
+                && (!vkd3d_system_value_builtins[i].environment
+                || vkd3d_system_value_builtins[i].environment == environment))
+            return &vkd3d_system_value_builtins[i].builtin;
+    }
+
+    FIXME("Unhandled builtin (sysval %#x).\n", sysval);
+
+    return NULL;
+}
+
+static const struct vkd3d_spirv_builtin *get_spirv_builtin_for_register(
+        enum vkd3d_shader_register_type reg_type)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_register_builtins); ++i)
+    {
+        if (vkd3d_register_builtins[i].reg_type == reg_type)
+            return &vkd3d_register_builtins[i].builtin;
+    }
+
+    return NULL;
+}
+
+static const struct vkd3d_spirv_builtin *vkd3d_get_spirv_builtin(const struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_register_type reg_type, enum vkd3d_shader_input_sysval_semantic sysval)
+{
+    const struct vkd3d_spirv_builtin *builtin;
+
+    if ((builtin = get_spirv_builtin_for_sysval(compiler, sysval)))
+        return builtin;
+    if ((builtin = get_spirv_builtin_for_register(reg_type)))
+        return builtin;
+
+    if (sysval != VKD3D_SIV_NONE || (reg_type != VKD3DSPR_OUTPUT && reg_type != VKD3DSPR_COLOROUT))
+        FIXME("Unhandled builtin (register type %#x, sysval %#x).\n", reg_type, sysval);
+    return NULL;
+}
+
+static const struct vkd3d_shader_signature_element *vkd3d_find_signature_element_for_reg(
+        const struct vkd3d_shader_signature *signature, unsigned int *signature_element_index,
+        unsigned int reg_idx, DWORD write_mask)
+{
+    unsigned int signature_idx;
+
+    for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
+    {
+        if (signature->elements[signature_idx].register_index == reg_idx
+                && (signature->elements[signature_idx].mask & write_mask) == write_mask)
+        {
+            if (signature_element_index)
+                *signature_element_index = signature_idx;
+            return &signature->elements[signature_idx];
+        }
+    }
+
+    FIXME("Could not find shader signature element (register %u, write mask %#x).\n",
+            reg_idx, write_mask);
+    if (signature_element_index)
+        *signature_element_index = ~0u;
+    return NULL;
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_invocation_id(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_shader_register r;
+
+    assert(compiler->shader_type == VKD3D_SHADER_TYPE_HULL);
+
+    memset(&r, 0, sizeof(r));
+    r.type = VKD3DSPR_OUTPOINTID;
+    r.idx[0].offset = ~0u;
+    r.idx[1].offset = ~0u;
+    return vkd3d_dxbc_compiler_get_register_id(compiler, &r);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_load_invocation_id(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, id;
+
+    id = vkd3d_dxbc_compiler_get_invocation_id(compiler);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1);
+    return vkd3d_spirv_build_op_load(builder, type_id, id, SpvMemoryAccessMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_shader_phase_name(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t id, const struct vkd3d_shader_phase *phase, const char *suffix)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const char *name;
+
+    if (!suffix)
+        suffix = "";
+
+    switch (phase->type)
+    {
+        case VKD3DSIH_HS_CONTROL_POINT_PHASE:
+            name = "control";
+            break;
+        case VKD3DSIH_HS_FORK_PHASE:
+            name = "fork";
+            break;
+        case VKD3DSIH_HS_JOIN_PHASE:
+            name = "join";
+            break;
+        default:
+            ERR("Invalid phase type %#x.\n", phase->type);
+            return;
+    }
+    vkd3d_spirv_build_op_name(builder, id, "%s%u%s", name, phase->idx, suffix);
+}
+
+static void vkd3d_dxbc_compiler_begin_shader_phase(struct vkd3d_dxbc_compiler *compiler,
+        struct vkd3d_shader_phase *phase)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t void_id, function_type_id;
+    unsigned int param_count;
+    uint32_t param_type_id;
+
+    if (phase->instance_count)
+    {
+        param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        param_count = 1;
+    }
+    else
+    {
+        param_count = 0;
+    }
+
+    phase->function_id = vkd3d_spirv_alloc_id(builder);
+
+    void_id = vkd3d_spirv_get_op_type_void(builder);
+    function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, &param_type_id, param_count);
+    vkd3d_spirv_build_op_function(builder, void_id, phase->function_id,
+            SpvFunctionControlMaskNone, function_type_id);
+
+    if (phase->instance_count)
+        phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id);
+
+    vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
+    phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+
+    vkd3d_dxbc_compiler_emit_shader_phase_name(compiler, phase->function_id, phase, NULL);
+}
+
+static const struct vkd3d_shader_phase *vkd3d_dxbc_compiler_get_current_shader_phase(
+        struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_shader_phase *phase;
+
+    if (!compiler->shader_phase_count)
+        return NULL;
+
+    phase = &compiler->shader_phases[compiler->shader_phase_count - 1];
+    if (!phase->function_id)
+        vkd3d_dxbc_compiler_begin_shader_phase(compiler, phase);
+    return phase;
+}
+
+static void vkd3d_dxbc_compiler_decorate_xfb_output(struct vkd3d_dxbc_compiler *compiler,
+        uint32_t id, unsigned int component_count, const struct vkd3d_shader_signature_element *signature_element)
+{
+    const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info;
+    const struct vkd3d_shader_transform_feedback_element *xfb_element;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int offset, stride, i;
+
+    if (!xfb_info)
+        return;
+
+    offset = 0;
+    xfb_element = NULL;
+    for (i = 0; i < xfb_info->element_count; ++i)
+    {
+        const struct vkd3d_shader_transform_feedback_element *e = &xfb_info->elements[i];
+
+        if (e->stream_index == signature_element->stream_index
+                && !ascii_strcasecmp(e->semantic_name, signature_element->semantic_name)
+                && e->semantic_index == signature_element->semantic_index)
+        {
+            xfb_element = e;
+            break;
+        }
+
+        offset += 4 * e->component_count;
+    }
+
+    if (!xfb_element)
+        return;
+
+    if (xfb_element->component_index || xfb_element->component_count > component_count)
+    {
+        FIXME("Unhandled component range %u, %u.\n", xfb_element->component_index, xfb_element->component_count);
+        return;
+    }
+
+    if (xfb_element->output_slot < xfb_info->buffer_stride_count)
+    {
+        stride = xfb_info->buffer_strides[xfb_element->output_slot];
+    }
+    else
+    {
+        stride = 0;
+        for (i = 0; i < xfb_info->element_count; ++i)
+        {
+            const struct vkd3d_shader_transform_feedback_element *e = &xfb_info->elements[i];
+
+            if (e->stream_index == xfb_element->stream_index && e->output_slot == xfb_element->output_slot)
+                stride += 4 * e->component_count;
+        }
+    }
+
+    vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationXfbBuffer, xfb_element->output_slot);
+    vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationXfbStride, stride);
+    vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationOffset, offset);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_builtin_variable(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_spirv_builtin *builtin, SpvStorageClass storage_class, unsigned int array_size)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t id;
+
+    array_size = max(array_size, builtin->spirv_array_size);
+
+    id = vkd3d_dxbc_compiler_emit_array_variable(compiler,
+            &builder->global_stream, storage_class,
+            builtin->component_type, builtin->component_count, array_size);
+    vkd3d_spirv_add_iface_variable(builder, id);
+    vkd3d_dxbc_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && storage_class == SpvStorageClassInput
+            && builtin->component_type != VKD3D_SHADER_COMPONENT_FLOAT
+            && builtin->component_type != VKD3D_SHADER_COMPONENT_BOOL)
+        vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationFlat, NULL, 0);
+
+    return id;
+}
+
+static bool needs_private_io_variable(const struct vkd3d_shader_signature *signature,
+        unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin,
+        unsigned int *component_count, unsigned int *out_write_mask)
+{
+    unsigned int write_mask = 0;
+    bool have_sysval = false;
+    unsigned int i, count;
+
+    if (*component_count == VKD3D_VEC4_SIZE)
+        return false;
+
+    for (i = 0, count = 0; i < signature->element_count; ++i)
+    {
+        const struct vkd3d_shader_signature_element *current = &signature->elements[i];
+
+        if (current->register_index != reg_idx)
+            continue;
+
+        write_mask |= current->mask;
+        ++count;
+
+        if (current->sysval_semantic)
+            have_sysval = true;
+    }
+
+    if (count == 1)
+        return false;
+
+    if (builtin || have_sysval)
+        return true;
+
+    if (!vkd3d_bitmask_is_contiguous(write_mask))
+    {
+        FIXME("Write mask %#x is non-contiguous.\n", write_mask);
+        return true;
+    }
+
+    assert(vkd3d_write_mask_component_count(write_mask) >= *component_count);
+    *component_count = vkd3d_write_mask_component_count(write_mask);
+    *out_write_mask = write_mask;
+    return false;
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_input(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval,
+        enum vkd3d_shader_interpolation_mode interpolation_mode)
+{
+    unsigned int component_idx, component_count, input_component_count;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_signature_element *signature_element;
+    const struct vkd3d_shader_signature *shader_signature;
+    const struct vkd3d_shader_register *reg = &dst->reg;
+    enum vkd3d_shader_component_type component_type;
+    uint32_t type_id, ptr_type_id, float_type_id;
+    const struct vkd3d_spirv_builtin *builtin;
+    uint32_t val_id, input_id, var_id;
+    struct vkd3d_symbol reg_symbol;
+    struct vkd3d_symbol tmp_symbol;
+    SpvStorageClass storage_class;
+    struct rb_entry *entry = NULL;
+    bool use_private_var = false;
+    unsigned int write_mask;
+    unsigned int array_size;
+    unsigned int reg_idx;
+    uint32_t i, index;
+
+    assert(!reg->idx[0].rel_addr);
+    assert(!reg->idx[1].rel_addr);
+
+    if (reg->idx[1].offset != ~0u)
+    {
+        array_size = reg->idx[0].offset;
+        reg_idx = reg->idx[1].offset;
+    }
+    else
+    {
+        array_size = 0;
+        reg_idx = reg->idx[0].offset;
+    }
+
+    shader_signature = reg->type == VKD3DSPR_PATCHCONST
+            ? compiler->patch_constant_signature : compiler->input_signature;
+
+    if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature,
+            NULL, reg_idx, dst->write_mask)))
+    {
+        FIXME("No signature element for shader input, ignoring shader input.\n");
+        return 0;
+    }
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && !sysval && signature_element->sysval_semantic)
+        sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic);
+
+    builtin = get_spirv_builtin_for_sysval(compiler, sysval);
+
+    write_mask = signature_element->mask;
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    if (builtin)
+    {
+        component_type = builtin->component_type;
+        input_component_count = builtin->component_count;
+        component_idx = 0;
+    }
+    else
+    {
+        component_type = signature_element->component_type;
+        input_component_count = vkd3d_write_mask_component_count(signature_element->mask);
+        component_idx = vkd3d_write_mask_get_component_idx(signature_element->mask);
+    }
+
+    if ((use_private_var = builtin && builtin->fixup_pfn))
+    {
+        component_count = VKD3D_VEC4_SIZE;
+        write_mask = VKD3DSP_WRITEMASK_ALL;
+    }
+    else if (needs_private_io_variable(shader_signature, reg_idx, builtin, &input_component_count, &write_mask))
+    {
+        use_private_var = true;
+        component_count = VKD3D_VEC4_SIZE;
+        write_mask = VKD3DSP_WRITEMASK_ALL;
+    }
+    else
+    {
+        component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+    }
+
+    storage_class = SpvStorageClassInput;
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+
+    if (builtin)
+    {
+        input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
+        entry = rb_get(&compiler->symbol_table, &reg_symbol);
+    }
+    else if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+    {
+        input_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
+    }
+    else
+    {
+        input_id = 0;
+
+        if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && reg->type == VKD3DSPR_INCONTROLPOINT)
+        {
+            tmp_symbol = reg_symbol;
+            tmp_symbol.key.reg.type = VKD3DSPR_INPUT;
+
+            if ((entry = rb_get(&compiler->symbol_table, &tmp_symbol)))
+            {
+                tmp_symbol = *RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry);
+                tmp_symbol.key.reg.type = VKD3DSPR_INCONTROLPOINT;
+                vkd3d_dxbc_compiler_put_symbol(compiler, &tmp_symbol);
+
+                input_id = tmp_symbol.id;
+            }
+        }
+
+        if (!entry)
+        {
+            unsigned int location = reg_idx;
+
+            if (reg->type == VKD3DSPR_PATCHCONST)
+                location += compiler->input_signature->element_count;
+
+            input_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+                    storage_class, component_type, input_component_count, array_size);
+            vkd3d_spirv_add_iface_variable(builder, input_id);
+            vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location);
+            if (component_idx)
+                vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx);
+
+            vkd3d_dxbc_compiler_emit_interpolation_decorations(compiler, input_id, interpolation_mode);
+        }
+    }
+
+    if (reg->type == VKD3DSPR_PATCHCONST)
+        vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
+
+    if (entry || !use_private_var)
+    {
+        var_id = input_id;
+    }
+    else
+    {
+        storage_class = SpvStorageClassPrivate;
+        var_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+                storage_class, VKD3D_SHADER_COMPONENT_FLOAT, component_count, array_size);
+    }
+
+    if (!entry)
+    {
+        vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+                use_private_var ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, write_mask);
+        vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+
+        vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    }
+
+    if (use_private_var)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count);
+        for (i = 0; i < max(array_size, 1); ++i)
+        {
+            struct vkd3d_shader_register dst_reg = *reg;
+            dst_reg.data_type = VKD3D_DATA_FLOAT;
+
+            val_id = input_id;
+            if (array_size)
+            {
+                ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id);
+                index = vkd3d_dxbc_compiler_get_constant_uint(compiler, i);
+                val_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, input_id, index);
+                dst_reg.idx[0].offset = i;
+            }
+            val_id = vkd3d_spirv_build_op_load(builder, type_id, val_id, SpvMemoryAccessMaskNone);
+
+            if (builtin && builtin->fixup_pfn)
+                val_id = builtin->fixup_pfn(compiler, val_id);
+
+            if (component_type != VKD3D_SHADER_COMPONENT_FLOAT)
+            {
+                float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, input_component_count);
+                val_id = vkd3d_spirv_build_op_bitcast(builder, float_type_id, val_id);
+            }
+
+            val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id,
+                    vkd3d_write_mask_from_component_count(input_component_count) << component_idx,
+                    VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_NO_SWIZZLE, dst->write_mask);
+
+            vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst_reg, dst->write_mask, val_id);
+        }
+    }
+
+    return input_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_input_register(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_register *reg = &dst->reg;
+    const struct vkd3d_spirv_builtin *builtin;
+    struct vkd3d_symbol reg_symbol;
+    struct rb_entry *entry;
+    uint32_t input_id;
+
+    assert(!reg->idx[0].rel_addr);
+    assert(!reg->idx[1].rel_addr);
+    assert(reg->idx[1].offset == ~0u);
+
+    if (!(builtin = get_spirv_builtin_for_register(reg->type)))
+    {
+        FIXME("Unhandled register %#x.\n", reg->type);
+        return;
+    }
+
+    /* vPrim may be declared in multiple hull shader phases. */
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+        return;
+
+    input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassInput, 0);
+
+    vkd3d_symbol_set_register_info(&reg_symbol, input_id, SpvStorageClassInput,
+            builtin->component_type, vkd3d_write_mask_from_component_count(builtin->component_count));
+    reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, input_id, reg);
+}
+
+static void vkd3d_dxbc_compiler_emit_shader_phase_input(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_register *reg = &dst->reg;
+    struct vkd3d_symbol reg_symbol;
+    uint32_t val_id;
+
+    switch (reg->type)
+    {
+        case VKD3DSPR_INPUT:
+        case VKD3DSPR_INCONTROLPOINT:
+            vkd3d_dxbc_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE);
+            return;
+        case VKD3DSPR_PRIMID:
+            vkd3d_dxbc_compiler_emit_input_register(compiler, dst);
+            return;
+        case VKD3DSPR_FORKINSTID:
+        case VKD3DSPR_JOININSTID:
+            val_id = phase->instance_id;
+            break;
+        case VKD3DSPR_OUTPOINTID: /* Emitted in vkd3d_dxbc_compiler_emit_initial_declarations(). */
+        case VKD3DSPR_OUTCONTROLPOINT: /* See vkd3d_dxbc_compiler_leave_shader_phase(). */
+            return;
+        default:
+            FIXME("Unhandled shader phase input register %#x.\n", reg->type);
+            return;
+    }
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, val_id,
+            SpvStorageClassMax /* Intermediate value */,
+            VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0);
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, val_id, reg);
+}
+
+static unsigned int vkd3d_dxbc_compiler_get_output_variable_index(
+        struct vkd3d_dxbc_compiler *compiler, unsigned int register_idx)
+{
+    if (register_idx == ~0u) /* oDepth */
+        return ARRAY_SIZE(compiler->private_output_variable) - 1;
+    assert(register_idx < ARRAY_SIZE(compiler->private_output_variable) - 1);
+    return register_idx;
+}
+
+static unsigned int get_shader_output_swizzle(const struct vkd3d_dxbc_compiler *compiler,
+        unsigned int register_idx)
+{
+    const struct vkd3d_shader_spirv_target_info *info;
+
+    if (!(info = compiler->spirv_target_info))
+        return VKD3D_SHADER_NO_SWIZZLE;
+    if (register_idx >= info->output_swizzle_count)
+        return VKD3D_SHADER_NO_SWIZZLE;
+    return info->output_swizzles[register_idx];
+}
+
+static bool is_dual_source_blending(const struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+
+    return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending;
+}
+
+static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signature_element *e,
+        uint32_t *mask)
+{
+    if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
+    {
+        FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index);
+        return;
+    }
+
+    *mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
+}
+
+static uint32_t calculate_sysval_array_mask(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval)
+{
+    const struct vkd3d_shader_signature_element *e;
+    const struct vkd3d_spirv_builtin *sig_builtin;
+    const struct vkd3d_spirv_builtin *builtin;
+    uint32_t signature_idx, mask = 0;
+
+    if (!(builtin = get_spirv_builtin_for_sysval(compiler, sysval)))
+    {
+        FIXME("Unhandled sysval %#x.\n", sysval);
+        return 0;
+    }
+
+    for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
+    {
+        e = &signature->elements[signature_idx];
+
+        sig_builtin = get_spirv_builtin_for_sysval(compiler,
+                vkd3d_siv_from_sysval_indexed(e->sysval_semantic, e->semantic_index));
+
+        if (sig_builtin && sig_builtin->spirv_builtin == builtin->spirv_builtin)
+            mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * sig_builtin->member_idx);
+    }
+
+    return mask;
+}
+
+/* Emits arrayed SPIR-V built-in variables. */
+static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_signature *output_signature = compiler->output_signature;
+    uint32_t clip_distance_mask = 0, clip_distance_id = 0;
+    uint32_t cull_distance_mask = 0, cull_distance_id = 0;
+    const struct vkd3d_spirv_builtin *builtin;
+    unsigned int i, count;
+
+    for (i = 0; i < output_signature->element_count; ++i)
+    {
+        const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
+
+        switch (e->sysval_semantic)
+        {
+            case VKD3D_SHADER_SV_CLIP_DISTANCE:
+                calculate_clip_or_cull_distance_mask(e, &clip_distance_mask);
+                break;
+
+            case VKD3D_SHADER_SV_CULL_DISTANCE:
+                calculate_clip_or_cull_distance_mask(e, &cull_distance_mask);
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    if (clip_distance_mask)
+    {
+        count = vkd3d_popcount(clip_distance_mask);
+        builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CLIP_DISTANCE);
+        clip_distance_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler,
+                builtin, SpvStorageClassOutput, count);
+    }
+
+    if (cull_distance_mask)
+    {
+        count = vkd3d_popcount(cull_distance_mask);
+        builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CULL_DISTANCE);
+        cull_distance_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler,
+                builtin, SpvStorageClassOutput, count);
+    }
+
+    for (i = 0; i < output_signature->element_count; ++i)
+    {
+        const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
+
+        switch (e->sysval_semantic)
+        {
+            case VKD3D_SHADER_SV_CLIP_DISTANCE:
+                compiler->output_info[i].id = clip_distance_id;
+                compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT;
+                compiler->output_info[i].array_element_mask = clip_distance_mask;
+                break;
+
+            case VKD3D_SHADER_SV_CULL_DISTANCE:
+                compiler->output_info[i].id = cull_distance_id;
+                compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT;
+                compiler->output_info[i].array_element_mask = cull_distance_mask;
+                break;
+
+            default:
+                break;
+        }
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_output_register(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_register *reg = &dst->reg;
+    const struct vkd3d_spirv_builtin *builtin;
+    struct vkd3d_symbol reg_symbol;
+    uint32_t output_id;
+
+    assert(!reg->idx[0].rel_addr);
+    assert(!reg->idx[1].rel_addr);
+    assert(reg->idx[1].offset == ~0u);
+
+    if (!(builtin = get_spirv_builtin_for_register(reg->type)))
+    {
+        FIXME("Unhandled register %#x.\n", reg->type);
+        return;
+    }
+
+    output_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0);
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, output_id, SpvStorageClassOutput,
+            builtin->component_type, vkd3d_write_mask_from_component_count(builtin->component_count));
+    reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, output_id, reg);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_shader_phase_builtin_variable(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_phase *phase, const struct vkd3d_spirv_builtin *builtin)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t *variable_id, id;
+
+    variable_id = NULL;
+
+    if (builtin->spirv_builtin == SpvBuiltInTessLevelOuter)
+        variable_id = &compiler->hs.tess_level_outer_id;
+    else if (builtin->spirv_builtin == SpvBuiltInTessLevelInner)
+        variable_id = &compiler->hs.tess_level_inner_id;
+
+    if (variable_id && *variable_id)
+        return *variable_id;
+
+    id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0);
+    if (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE)
+        vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
+
+    if (variable_id)
+        *variable_id = id;
+    return id;
+}
+
+static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_signature_element *signature_element;
+    const struct vkd3d_shader_signature *shader_signature;
+    const struct vkd3d_shader_register *reg = &dst->reg;
+    unsigned int component_idx, output_component_count;
+    enum vkd3d_shader_component_type component_type;
+    const struct vkd3d_spirv_builtin *builtin;
+    const struct vkd3d_shader_phase *phase;
+    struct vkd3d_symbol reg_symbol;
+    SpvStorageClass storage_class;
+    struct rb_entry *entry = NULL;
+    unsigned int signature_idx;
+    bool use_private_variable;
+    unsigned int write_mask;
+    unsigned int array_size;
+    bool is_patch_constant;
+    uint32_t id, var_id;
+
+    phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler);
+    is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE);
+
+    shader_signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
+
+    array_size = is_control_point_phase(phase) ? compiler->output_control_point_count : 0;
+
+    if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature,
+            &signature_idx, reg->idx[0].offset, dst->write_mask)))
+    {
+        FIXME("No signature element for shader output, ignoring shader output.\n");
+        return;
+    }
+
+    builtin = vkd3d_get_spirv_builtin(compiler, dst->reg.type, sysval);
+
+    write_mask = signature_element->mask;
+
+    component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
+    output_component_count = vkd3d_write_mask_component_count(signature_element->mask);
+    if (builtin)
+    {
+        component_type = builtin->component_type;
+        if (!builtin->spirv_array_size)
+            output_component_count = builtin->component_count;
+    }
+    else
+    {
+        component_type = signature_element->component_type;
+    }
+
+    storage_class = SpvStorageClassOutput;
+
+    if ((use_private_variable = builtin && builtin->spirv_array_size))
+        write_mask = VKD3DSP_WRITEMASK_ALL;
+    else if (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE
+            || needs_private_io_variable(shader_signature, signature_element->register_index,
+                    builtin, &output_component_count, &write_mask)
+            || is_patch_constant)
+    {
+        use_private_variable = true;
+        write_mask = VKD3DSP_WRITEMASK_ALL;
+    }
+    else
+    {
+        component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+    }
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+
+    if (compiler->output_info[signature_idx].id)
+    {
+        id = compiler->output_info[signature_idx].id;
+        if (compiler->output_info[signature_idx].array_element_mask)
+        {
+            use_private_variable = true;
+            write_mask = VKD3DSP_WRITEMASK_ALL;
+            entry = rb_get(&compiler->symbol_table, &reg_symbol);
+        }
+    }
+    else if (!use_private_variable && (entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+    {
+        id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
+    }
+    else
+    {
+        if (builtin)
+        {
+            if (phase)
+                id = vkd3d_dxbc_compiler_emit_shader_phase_builtin_variable(compiler, phase, builtin);
+            else
+                id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
+
+            if (builtin->spirv_array_size)
+                compiler->output_info[signature_idx].array_element_mask =
+                        calculate_sysval_array_mask(compiler, shader_signature, sysval);
+
+            vkd3d_dxbc_compiler_emit_register_execution_mode(compiler, &dst->reg);
+
+            if (component_idx)
+                FIXME("Unhandled component index %u.\n", component_idx);
+        }
+        else
+        {
+            unsigned int location = reg->idx[0].offset;
+
+            if (is_patch_constant)
+                location += compiler->output_signature->element_count;
+
+            id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+                    storage_class, component_type, output_component_count, array_size);
+            vkd3d_spirv_add_iface_variable(builder, id);
+
+            if (is_dual_source_blending(compiler) && reg->idx[0].offset < 2)
+            {
+                vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, 0);
+                vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationIndex, reg->idx[0].offset);
+            }
+            else
+            {
+                vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, location);
+            }
+
+            if (component_idx)
+                vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx);
+        }
+
+        if (is_patch_constant)
+            vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
+
+        vkd3d_dxbc_compiler_decorate_xfb_output(compiler, id, output_component_count, signature_element);
+    }
+
+    compiler->output_info[signature_idx].id = id;
+    compiler->output_info[signature_idx].component_type = component_type;
+
+    if (use_private_variable)
+        storage_class = SpvStorageClassPrivate;
+
+    if (entry)
+        var_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
+    else if (!use_private_variable)
+        var_id = id;
+    else if (is_patch_constant)
+        var_id = compiler->hs.patch_constants_id;
+    else
+        var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
+                storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    if (!entry)
+    {
+        vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+                use_private_variable ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, write_mask);
+        reg_symbol.info.reg.is_aggregate = use_private_variable ? is_patch_constant : array_size;
+        if (!use_private_variable && is_control_point_phase(phase))
+        {
+            reg_symbol.info.reg.member_idx = vkd3d_dxbc_compiler_get_invocation_id(compiler);
+            reg_symbol.info.reg.is_dynamically_indexed = true;
+        }
+        else if (is_patch_constant)
+        {
+            reg_symbol.info.reg.member_idx = reg->idx[0].offset;
+        }
+
+        vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+
+        if (!is_patch_constant)
+            vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    }
+
+    if (use_private_variable)
+    {
+        unsigned int idx = vkd3d_dxbc_compiler_get_output_variable_index(compiler, reg->idx[0].offset);
+        compiler->private_output_variable[idx] = var_id;
+        compiler->private_output_variable_write_mask[idx] |= dst->write_mask;
+        if (is_patch_constant)
+            compiler->private_output_variable_array_idx[idx] = vkd3d_dxbc_compiler_get_constant_uint(
+                    compiler, reg->idx[0].offset);
+        if (!compiler->epilogue_function_id)
+            compiler->epilogue_function_id = vkd3d_spirv_alloc_id(builder);
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_output_array_index(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_signature_element *e)
+{
+    enum vkd3d_shader_input_sysval_semantic sysval;
+    const struct vkd3d_spirv_builtin *builtin;
+
+    sysval = vkd3d_siv_from_sysval_indexed(e->sysval_semantic, e->semantic_index);
+    builtin = get_spirv_builtin_for_sysval(compiler, sysval);
+
+    switch (sysval)
+    {
+        case VKD3D_SIV_LINE_DETAIL_TESS_FACTOR:
+        case VKD3D_SIV_LINE_DENSITY_TESS_FACTOR:
+            return builtin->member_idx;
+        default:
+            return e->semantic_index;
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_signature_element *output,
+        const struct vkd3d_shader_output_info *output_info,
+        uint32_t output_index_id, uint32_t val_id, unsigned int write_mask)
+{
+    unsigned int dst_write_mask, use_mask, uninit_mask, swizzle, mask;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
+    unsigned int i, index, array_idx;
+    uint32_t output_id;
+
+    dst_write_mask = output->mask;
+    write_mask &= dst_write_mask;
+    use_mask = output->used_mask;
+
+    if (!write_mask)
+        return;
+
+    if (output_info->component_type != VKD3D_SHADER_COMPONENT_FLOAT)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, output_info->component_type, VKD3D_VEC4_SIZE);
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+
+    swizzle = get_shader_output_swizzle(compiler, output->register_index);
+    uninit_mask = dst_write_mask & ~use_mask;
+    if (uninit_mask)
+    {
+        /* Set values to 0 for not initialized shader output components. */
+        write_mask |= uninit_mask;
+        zero_id = vkd3d_dxbc_compiler_get_constant_vector(compiler,
+                output_info->component_type, VKD3D_VEC4_SIZE, 0);
+        val_id = vkd3d_dxbc_compiler_emit_vector_shuffle(compiler,
+                zero_id, val_id, swizzle, uninit_mask, output_info->component_type,
+                vkd3d_write_mask_component_count(write_mask));
+    }
+    else
+    {
+        val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler,
+                val_id, VKD3DSP_WRITEMASK_ALL, output_info->component_type, swizzle, write_mask);
+    }
+
+    output_id = output_info->id;
+    if (output_index_id)
+    {
+        type_id = vkd3d_spirv_get_type_id(builder,
+                output_info->component_type, vkd3d_write_mask_component_count(dst_write_mask));
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
+        output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id);
+    }
+
+    if (!output_info->array_element_mask)
+    {
+        vkd3d_dxbc_compiler_emit_store(compiler,
+                output_id, dst_write_mask, output_info->component_type, SpvStorageClassOutput, write_mask, val_id);
+        return;
+    }
+
+    type_id = vkd3d_spirv_get_type_id(builder, output_info->component_type, 1);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
+    mask = output_info->array_element_mask;
+    array_idx = vkd3d_dxbc_compiler_get_output_array_index(compiler, output);
+    mask &= (1u << (array_idx * VKD3D_VEC4_SIZE)) - 1;
+    for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        chain_id = vkd3d_spirv_build_op_access_chain1(builder,
+                ptr_type_id, output_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, index));
+        object_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, write_mask,
+                output_info->component_type, VKD3D_SHADER_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i);
+        vkd3d_dxbc_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0,
+                output_info->component_type, SpvStorageClassOutput, VKD3DSP_WRITEMASK_0 << i, object_id);
+        ++index;
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_shader_epilogue_function(struct vkd3d_dxbc_compiler *compiler)
+{
+    uint32_t param_type_id[MAX_REG_OUTPUT + 1], param_id[MAX_REG_OUTPUT + 1] = {0};
+    uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_signature *signature;
+    const struct vkd3d_shader_phase *phase;
+    uint32_t output_index_id = 0;
+    bool is_patch_constant;
+    unsigned int i, count;
+    DWORD variable_idx;
+
+    STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_id));
+    STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_type_id));
+    STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_array_idx));
+    STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask));
+
+    phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler);
+    is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE);
+
+    signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
+
+    function_id = compiler->epilogue_function_id;
+
+    void_id = vkd3d_spirv_get_op_type_void(builder);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
+    for (i = 0, count = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
+    {
+        if (compiler->private_output_variable[i])
+            param_type_id[count++] = ptr_type_id;
+    }
+    function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, param_type_id, count);
+
+    vkd3d_spirv_build_op_function(builder, void_id, function_id,
+            SpvFunctionControlMaskNone, function_type_id);
+
+    for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
+    {
+        if (compiler->private_output_variable[i])
+            param_id[i] = vkd3d_spirv_build_op_function_parameter(builder, ptr_type_id);
+    }
+
+    vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
+
+    for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
+    {
+        if (compiler->private_output_variable[i])
+            param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone);
+    }
+
+    if (is_control_point_phase(phase))
+        output_index_id = vkd3d_dxbc_compiler_emit_load_invocation_id(compiler);
+
+    for (i = 0; i < signature->element_count; ++i)
+    {
+        variable_idx = vkd3d_dxbc_compiler_get_output_variable_index(compiler,
+                signature->elements[i].register_index);
+
+        if (!param_id[variable_idx])
+            continue;
+
+        vkd3d_dxbc_compiler_emit_store_shader_output(compiler,
+                &signature->elements[i], &compiler->output_info[i], output_index_id,
+                param_id[variable_idx], compiler->private_output_variable_write_mask[variable_idx]);
+    }
+
+    vkd3d_spirv_build_op_return(&compiler->spirv_builder);
+    vkd3d_spirv_build_op_function_end(builder);
+
+    memset(compiler->private_output_variable, 0, sizeof(compiler->private_output_variable));
+    memset(compiler->private_output_variable_array_idx, 0, sizeof(compiler->private_output_variable_array_idx));
+    memset(compiler->private_output_variable_write_mask, 0, sizeof(compiler->private_output_variable_write_mask));
+    compiler->epilogue_function_id = 0;
+}
+
+static void vkd3d_dxbc_compiler_emit_hull_shader_builtins(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_shader_dst_param dst;
+
+    memset(&dst, 0, sizeof(dst));
+    dst.reg.type = VKD3DSPR_OUTPOINTID;
+    dst.reg.idx[0].offset = ~0u;
+    dst.reg.idx[1].offset = ~0u;
+    dst.write_mask = VKD3DSP_WRITEMASK_0;
+    vkd3d_dxbc_compiler_emit_input_register(compiler, &dst);
+}
+
+static void vkd3d_dxbc_compiler_emit_hull_shader_patch_constants(struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_signature *signature = compiler->patch_constant_signature;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t register_count = 0;
+    unsigned int signature_idx;
+
+    for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
+        register_count = max(register_count, signature->elements[signature_idx].register_index + 1);
+
+    if (!register_count)
+        return;
+
+    compiler->hs.patch_constants_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+            SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, register_count);
+    vkd3d_spirv_build_op_name(builder, compiler->hs.patch_constants_id, "opc");
+}
+
+static void vkd3d_dxbc_compiler_emit_initial_declarations(struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    switch (compiler->shader_type)
+    {
+        case VKD3D_SHADER_TYPE_VERTEX:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelVertex);
+            break;
+        case VKD3D_SHADER_TYPE_HULL:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationControl);
+            vkd3d_dxbc_compiler_emit_hull_shader_builtins(compiler);
+            vkd3d_dxbc_compiler_emit_hull_shader_patch_constants(compiler);
+            break;
+        case VKD3D_SHADER_TYPE_DOMAIN:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationEvaluation);
+            break;
+        case VKD3D_SHADER_TYPE_GEOMETRY:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelGeometry);
+            builder->invocation_count = 1;
+            break;
+        case VKD3D_SHADER_TYPE_PIXEL:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelFragment);
+            vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeOriginUpperLeft, NULL, 0);
+            break;
+        case VKD3D_SHADER_TYPE_COMPUTE:
+            vkd3d_spirv_set_execution_model(builder, SpvExecutionModelGLCompute);
+            break;
+        default:
+            ERR("Invalid shader type %#x.\n", compiler->shader_type);
+    }
+
+    if (xfb_info && xfb_info->element_count)
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityTransformFeedback);
+        vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeXfb, NULL, 0);
+    }
+
+    if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
+    {
+        vkd3d_spirv_builder_begin_main_function(builder);
+
+        vkd3d_dxbc_compiler_emit_shader_signature_outputs(compiler);
+    }
+}
+
+static size_t vkd3d_dxbc_compiler_get_current_function_location(struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_phase *phase;
+
+    if ((phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler)))
+        return phase->function_location;
+
+    return builder->main_function_location;
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_global_flags(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    unsigned int flags = instruction->flags;
+
+    if (flags & VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL)
+    {
+        vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeEarlyFragmentTests, NULL, 0);
+        flags &= ~VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL;
+    }
+
+    if (flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS))
+        FIXME("Unhandled global flags %#x.\n", flags);
+    else
+        WARN("Unhandled global flags %#x.\n", flags);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_temps(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    size_t function_location;
+    unsigned int i;
+    uint32_t id;
+
+    function_location = vkd3d_dxbc_compiler_get_current_function_location(compiler);
+    vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
+
+    assert(!compiler->temp_count);
+    compiler->temp_count = instruction->declaration.count;
+    for (i = 0; i < compiler->temp_count; ++i)
+    {
+        id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->function_stream,
+                SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+        if (!i)
+            compiler->temp_id = id;
+        assert(id == compiler->temp_id + i);
+
+        vkd3d_spirv_build_op_name(builder, id, "r%u", i);
+    }
+
+    vkd3d_spirv_end_function_stream_insertion(builder);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_indexable_temp(struct vkd3d_dxbc_compiler *compiler,
+          const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_indexable_temp *temp = &instruction->declaration.indexable_temp;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_register reg;
+    struct vkd3d_symbol reg_symbol;
+    size_t function_location;
+    uint32_t id;
+
+    if (temp->component_count != 4)
+        FIXME("Unhandled component count %u.\n", temp->component_count);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.type = VKD3DSPR_IDXTEMP;
+    reg.idx[0].offset = temp->register_idx;
+    reg.idx[1].offset = ~0u;
+
+    function_location = vkd3d_dxbc_compiler_get_current_function_location(compiler);
+    vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
+
+    id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->function_stream,
+            SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, temp->register_size);
+
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, id, &reg);
+
+    vkd3d_spirv_end_function_stream_insertion(builder);
+
+    vkd3d_symbol_make_register(&reg_symbol, &reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, id,
+            SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+}
+
+static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_compiler *compiler)
+{
+    const SpvStorageClass storage_class = SpvStorageClassPushConstant;
+    uint32_t vec4_id, length_id, struct_id, pointer_type_id, var_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int i, j, count, reg_idx;
+    struct vkd3d_symbol reg_symbol;
+    uint32_t *member_ids;
+
+    count = 0;
+    for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
+    {
+        const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
+
+        if (cb->reg.type)
+            ++count;
+    }
+    if (!count)
+        return;
+
+    if (!(member_ids = vkd3d_calloc(count, sizeof(*member_ids))))
+        return;
+
+    vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+
+    for (i = 0, j = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
+    {
+        const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
+        if (!cb->reg.type)
+            continue;
+
+        length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb->size);
+        member_ids[j]  = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
+        vkd3d_spirv_build_op_decorate1(builder, member_ids[j], SpvDecorationArrayStride, 16);
+
+        ++j;
+    }
+
+    struct_id = vkd3d_spirv_build_op_type_struct(builder, member_ids, count);
+    vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
+    vkd3d_spirv_build_op_name(builder, struct_id, "push_cb");
+    vkd3d_free(member_ids);
+
+    pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
+    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            pointer_type_id, storage_class, 0);
+
+    for (i = 0, j = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
+    {
+        const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
+        if (!cb->reg.type)
+            continue;
+
+        reg_idx = cb->reg.idx[0].offset;
+        vkd3d_spirv_build_op_member_decorate1(builder, struct_id, j,
+                SpvDecorationOffset, cb->pc.offset);
+        vkd3d_spirv_build_op_member_name(builder, struct_id, j, "cb%u", reg_idx);
+
+        vkd3d_symbol_make_register(&reg_symbol, &cb->reg);
+        vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+                VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+        reg_symbol.info.reg.member_idx = j;
+        vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+
+        ++j;
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t vec4_id, array_type_id, length_id, struct_id, pointer_type_id, var_id;
+    const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const SpvStorageClass storage_class = SpvStorageClassUniform;
+    const struct vkd3d_shader_register *reg = &cb->src.reg;
+    struct vkd3d_push_constant_buffer_binding *push_cb;
+    struct vkd3d_symbol reg_symbol;
+
+    assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
+
+    if ((push_cb = vkd3d_dxbc_compiler_find_push_constant_buffer(compiler, cb)))
+    {
+        /* Push constant buffers are handled in
+         * vkd3d_dxbc_compiler_emit_push_constant_buffers().
+         */
+        unsigned int cb_size_in_bytes = cb->size * VKD3D_VEC4_SIZE * sizeof(uint32_t);
+        push_cb->reg = *reg;
+        push_cb->size = cb->size;
+        if (cb_size_in_bytes > push_cb->pc.size)
+        {
+            WARN("Constant buffer size %u exceeds push constant size %u.\n",
+                    cb_size_in_bytes, push_cb->pc.size);
+        }
+        return;
+    }
+
+    vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb->size);
+    array_type_id = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
+    vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 16);
+
+    struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1);
+    vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
+    vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
+    vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size);
+
+    pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
+    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            pointer_type_id, storage_class, 0);
+
+    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
+            var_id, reg, cb->register_space, cb->register_index, VKD3D_SHADER_RESOURCE_BUFFER, false);
+
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+            VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_immediate_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_immediate_constant_buffer *icb = instruction->declaration.icb;
+    uint32_t *elements, length_id, type_id, const_id, ptr_type_id, icb_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_register reg;
+    struct vkd3d_symbol reg_symbol;
+    unsigned int i;
+
+    if (!(elements = vkd3d_calloc(icb->vec4_count, sizeof(*elements))))
+        return;
+    for (i = 0; i < icb->vec4_count; ++i)
+        elements[i] = vkd3d_dxbc_compiler_get_constant(compiler,
+                VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &icb->data[4 * i]);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, icb->vec4_count);
+    type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
+    const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->vec4_count);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
+    icb_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            ptr_type_id, SpvStorageClassPrivate, const_id);
+    vkd3d_spirv_build_op_name(builder, icb_id, "icb");
+    vkd3d_free(elements);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.type = VKD3DSPR_IMMCONSTBUFFER;
+    vkd3d_symbol_make_register(&reg_symbol, &reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, icb_id, SpvStorageClassPrivate,
+            VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_sampler *sampler = &instruction->declaration.sampler;
+    const SpvStorageClass storage_class = SpvStorageClassUniformConstant;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_register *reg = &sampler->src.reg;
+    uint32_t type_id, ptr_type_id, var_id;
+    struct vkd3d_symbol reg_symbol;
+
+    vkd3d_symbol_make_sampler(&reg_symbol, reg);
+    reg_symbol.info.sampler.register_space = sampler->register_space;
+    reg_symbol.info.sampler.register_index = sampler->register_index;
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+
+    if (vkd3d_dxbc_compiler_has_combined_sampler(compiler, NULL, sampler))
+        return;
+
+    type_id = vkd3d_spirv_get_op_type_sampler(builder);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            ptr_type_id, storage_class, 0);
+
+    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler, var_id, reg,
+            sampler->register_space, sampler->register_index, VKD3D_SHADER_RESOURCE_NONE, false);
+
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+            VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+}
+
+static const struct vkd3d_spirv_resource_type *vkd3d_dxbc_compiler_enable_resource_type(
+        struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_resource_type resource_type, bool is_uav)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_spirv_resource_type *resource_type_info;
+
+    if (!(resource_type_info = vkd3d_get_spirv_resource_type(resource_type)))
+        return NULL;
+
+    if (resource_type_info->capability)
+        vkd3d_spirv_enable_capability(builder, resource_type_info->capability);
+    if (is_uav && resource_type_info->uav_capability)
+        vkd3d_spirv_enable_capability(builder, resource_type_info->uav_capability);
+
+    return resource_type_info;
+}
+
+static SpvImageFormat image_format_for_image_read(enum vkd3d_shader_component_type data_type)
+{
+    /* The following formats are supported by Direct3D 11 hardware for UAV
+     * typed loads. A newer hardware may support more formats for UAV typed
+     * loads (see StorageImageReadWithoutFormat SPIR-V capability).
+     */
+    switch (data_type)
+    {
+        case VKD3D_SHADER_COMPONENT_FLOAT:
+            return SpvImageFormatR32f;
+        case VKD3D_SHADER_COMPONENT_INT:
+            return SpvImageFormatR32i;
+        case VKD3D_SHADER_COMPONENT_UINT:
+            return SpvImageFormatR32ui;
+        default:
+            FIXME("Unhandled type %#x.\n", data_type);
+            return SpvImageFormatUnknown;
+    }
+}
+
+static const struct vkd3d_shader_descriptor_info *vkd3d_dxbc_compiler_get_descriptor_info(
+        struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_descriptor_type type,
+        unsigned int register_space, unsigned int register_index)
+{
+    const struct vkd3d_shader_scan_descriptor_info *descriptor_info = compiler->scan_descriptor_info;
+    const struct vkd3d_shader_descriptor_info *d;
+    unsigned int i;
+
+    for (i = 0; i < descriptor_info->descriptor_count; ++i)
+    {
+        d = &descriptor_info->descriptors[i];
+        if (d->type == type && d->register_space == register_space && d->register_index == register_index)
+            return d;
+    }
+
+    return NULL;
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_image_type_id(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, unsigned int register_space, unsigned int register_index,
+        const struct vkd3d_spirv_resource_type *resource_type_info, enum vkd3d_shader_component_type data_type,
+        bool raw_structured, uint32_t depth)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_descriptor_info *d;
+    uint32_t sampled_type_id;
+    SpvImageFormat format;
+
+    format = SpvImageFormatUnknown;
+    if (reg->type == VKD3DSPR_UAV)
+    {
+        d = vkd3d_dxbc_compiler_get_descriptor_info(compiler,
+                VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, register_space, register_index);
+        if (raw_structured || (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ))
+            format = image_format_for_image_read(data_type);
+    }
+
+    sampled_type_id = vkd3d_spirv_get_type_id(builder, data_type, 1);
+    return vkd3d_spirv_get_op_type_image(builder, sampled_type_id, resource_type_info->dim,
+            depth, resource_type_info->arrayed, resource_type_info->ms,
+            reg->type == VKD3DSPR_UAV ? 2 : 1, format);
+}
+
+static void vkd3d_dxbc_compiler_emit_combined_sampler_declarations(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *resource, unsigned int resource_space, unsigned int resource_index,
+        enum vkd3d_shader_resource_type resource_type, enum vkd3d_shader_component_type sampled_type,
+        unsigned int structure_stride, bool raw, const struct vkd3d_spirv_resource_type *resource_type_info)
+{
+    const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
+    const SpvStorageClass storage_class = SpvStorageClassUniformConstant;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_combined_resource_sampler *current;
+    uint32_t image_type_id, type_id, ptr_type_id, var_id;
+    enum vkd3d_shader_binding_flag resource_type_flag;
+    const struct vkd3d_shader_descriptor_info *d;
+    struct vkd3d_symbol symbol;
+    unsigned int i;
+    bool depth;
+
+    resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
+            ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
+
+    for (i = 0; i < shader_interface->combined_sampler_count; ++i)
+    {
+        current = &shader_interface->combined_samplers[i];
+
+        if (current->resource_space != resource_space || current->resource_index != resource_index)
+            continue;
+
+        if (!(current->flags & resource_type_flag))
+            continue;
+
+        if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
+            continue;
+
+        if (current->binding.count != 1)
+        {
+            FIXME("Descriptor arrays are not supported.\n");
+            vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
+                    "Combined descriptor binding for resource %u, space %u, "
+                    "and sampler %u, space %u has unsupported ‘count’ %u.",
+                    resource_index, resource_space, current->sampler_index,
+                    current->sampler_space, current->binding.count);
+        }
+
+        d = vkd3d_dxbc_compiler_get_descriptor_info(compiler,
+                VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, current->sampler_space, current->sampler_index);
+        depth = current->sampler_index != VKD3D_SHADER_DUMMY_SAMPLER_INDEX
+                && (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE);
+
+        image_type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, resource, resource_space,
+                resource_index, resource_type_info, sampled_type, structure_stride || raw, depth);
+        type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image_type_id);
+
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+        var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+                ptr_type_id, storage_class, 0);
+
+        vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, &current->binding);
+
+        if (current->sampler_index == VKD3D_SHADER_DUMMY_SAMPLER_INDEX)
+            vkd3d_spirv_build_op_name(builder, var_id, "t%u_%u_dummy_sampler", resource_space, resource_index);
+        else
+            vkd3d_spirv_build_op_name(builder, var_id, "t%u_%u_s%u_%u", resource_space, resource_index,
+                    current->sampler_space, current->sampler_index);
+
+        vkd3d_symbol_make_combined_sampler(&symbol, resource,
+                current->sampler_index == VKD3D_SHADER_DUMMY_SAMPLER_INDEX ? 0 : current->sampler_space,
+                current->sampler_index);
+        symbol.id = var_id;
+        symbol.info.resource.register_space = resource_space;
+        symbol.info.resource.register_index = resource_index;
+        symbol.info.resource.sampled_type = sampled_type;
+        symbol.info.resource.type_id = image_type_id;
+        symbol.info.resource.resource_type_info = resource_type_info;
+        symbol.info.resource.structure_stride = structure_stride;
+        symbol.info.resource.raw = raw;
+        symbol.info.resource.uav_counter_id = 0;
+        vkd3d_dxbc_compiler_put_symbol(compiler, &symbol);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type,
+        enum vkd3d_data_type resource_data_type, unsigned int structure_stride, bool raw)
+{
+    uint32_t counter_type_id, type_id, ptr_type_id, var_id, counter_var_id = 0;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    SpvStorageClass storage_class = SpvStorageClassUniformConstant;
+    const struct vkd3d_shader_register *reg = &resource->reg.reg;
+    const struct vkd3d_spirv_resource_type *resource_type_info;
+    unsigned int register_space = resource->register_space;
+    unsigned int register_index = resource->register_index;
+    enum vkd3d_shader_component_type sampled_type;
+    struct vkd3d_symbol resource_symbol;
+    bool is_uav;
+
+    is_uav = reg->type == VKD3DSPR_UAV;
+    if (!(resource_type_info = vkd3d_dxbc_compiler_enable_resource_type(compiler,
+            resource_type, is_uav)))
+    {
+        FIXME("Unrecognized resource type.\n");
+        return;
+    }
+
+    sampled_type = vkd3d_component_type_from_data_type(resource_data_type);
+
+    if (vkd3d_dxbc_compiler_has_combined_sampler(compiler, resource, NULL))
+    {
+        vkd3d_dxbc_compiler_emit_combined_sampler_declarations(compiler, reg, register_space,
+                register_index, resource_type, sampled_type, structure_stride, raw, resource_type_info);
+        return;
+    }
+
+    if (compiler->ssbo_uavs && is_uav && resource_type == VKD3D_SHADER_RESOURCE_BUFFER)
+    {
+        uint32_t array_type_id, struct_id;
+
+        type_id = vkd3d_spirv_get_type_id(builder, sampled_type, 1);
+
+        array_type_id = vkd3d_spirv_get_op_type_runtime_array(builder, type_id);
+        vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 4);
+
+        struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1);
+        vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBufferBlock, NULL, 0);
+        vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
+
+        type_id = struct_id;
+        storage_class = SpvStorageClassUniform;
+    }
+    else
+    {
+        type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, reg, register_space,
+                register_index, resource_type_info, sampled_type, structure_stride || raw, 0);
+    }
+
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            ptr_type_id, storage_class, 0);
+
+    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler, var_id, reg,
+            register_space, register_index, resource_type, false);
+
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+
+    if (is_uav)
+    {
+        const struct vkd3d_shader_descriptor_info *d;
+
+        d = vkd3d_dxbc_compiler_get_descriptor_info(compiler,
+                VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, register_space, register_index);
+
+        if (!(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ))
+            vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationNonReadable, NULL, 0);
+
+        if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER)
+        {
+            assert(structure_stride); /* counters are valid only for structured buffers */
+
+            counter_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+            if (vkd3d_dxbc_compiler_is_opengl_target(compiler))
+            {
+                vkd3d_spirv_enable_capability(builder, SpvCapabilityAtomicStorage);
+                storage_class = SpvStorageClassAtomicCounter;
+                ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, counter_type_id);
+            }
+            else if (compiler->ssbo_uavs)
+            {
+                uint32_t length_id, array_type_id, struct_id;
+
+                length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 1);
+                array_type_id = vkd3d_spirv_build_op_type_array(builder, counter_type_id, length_id);
+                vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 4);
+
+                struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1);
+                vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBufferBlock, NULL, 0);
+                vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
+
+                storage_class = SpvStorageClassUniform;
+                ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
+            }
+
+            counter_var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+                    ptr_type_id, storage_class, 0);
+
+            vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
+                    counter_var_id, reg, register_space, register_index, resource_type, true);
+
+            vkd3d_spirv_build_op_name(builder, counter_var_id, "u%u_counter", reg->idx[0].offset);
+        }
+    }
+
+    vkd3d_symbol_make_resource(&resource_symbol, reg);
+    resource_symbol.id = var_id;
+    resource_symbol.info.resource.register_space = register_space;
+    resource_symbol.info.resource.register_index = register_index;
+    resource_symbol.info.resource.sampled_type = sampled_type;
+    resource_symbol.info.resource.type_id = type_id;
+    resource_symbol.info.resource.resource_type_info = resource_type_info;
+    resource_symbol.info.resource.structure_stride = structure_stride;
+    resource_symbol.info.resource.raw = raw;
+    resource_symbol.info.resource.uav_counter_id = counter_var_id;
+    vkd3d_dxbc_compiler_put_symbol(compiler, &resource_symbol);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_resource(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_semantic *semantic = &instruction->declaration.semantic;
+
+    if (instruction->flags)
+        FIXME("Unhandled UAV flags %#x.\n", instruction->flags);
+
+    vkd3d_dxbc_compiler_emit_resource_declaration(compiler, &semantic->resource,
+            semantic->resource_type, semantic->resource_data_type, 0, false);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_resource_raw(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_raw_resource *resource = &instruction->declaration.raw_resource;
+
+    if (instruction->flags)
+        FIXME("Unhandled UAV flags %#x.\n", instruction->flags);
+
+    vkd3d_dxbc_compiler_emit_resource_declaration(compiler, &resource->resource,
+            VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_DATA_UINT, 0, true);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_resource_structured(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_structured_resource *resource = &instruction->declaration.structured_resource;
+    unsigned int stride = resource->byte_stride;
+
+    if (instruction->flags)
+        FIXME("Unhandled UAV flags %#x.\n", instruction->flags);
+
+    vkd3d_dxbc_compiler_emit_resource_declaration(compiler, &resource->resource,
+            VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_DATA_UINT, stride / 4, false);
+}
+
+static void vkd3d_dxbc_compiler_emit_workgroup_memory(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, unsigned int size, unsigned int structure_stride)
+{
+    uint32_t type_id, array_type_id, length_id, pointer_type_id, var_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const SpvStorageClass storage_class = SpvStorageClassWorkgroup;
+    struct vkd3d_symbol reg_symbol;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, size);
+    array_type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
+
+    pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, array_type_id);
+    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            pointer_type_id, storage_class, 0);
+
+    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+
+    vkd3d_symbol_make_register(&reg_symbol, reg);
+    vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
+            VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0);
+    reg_symbol.info.reg.structure_stride = structure_stride;
+    vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_tgsm_raw(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_tgsm_raw *tgsm_raw = &instruction->declaration.tgsm_raw;
+    vkd3d_dxbc_compiler_emit_workgroup_memory(compiler, &tgsm_raw->reg.reg,
+            tgsm_raw->byte_count / 4, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_tgsm_structured(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_tgsm_structured *tgsm_structured = &instruction->declaration.tgsm_structured;
+    unsigned int stride = tgsm_structured->byte_stride / 4;
+    vkd3d_dxbc_compiler_emit_workgroup_memory(compiler, &tgsm_structured->reg.reg,
+            tgsm_structured->structure_count * stride, stride);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_input(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst;
+    const struct vkd3d_shader_phase *phase;
+
+    if ((phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler)))
+        vkd3d_dxbc_compiler_emit_shader_phase_input(compiler, phase, dst);
+    else if (vkd3d_shader_register_is_input(&dst->reg) || dst->reg.type == VKD3DSPR_PATCHCONST)
+        vkd3d_dxbc_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE);
+    else
+        vkd3d_dxbc_compiler_emit_input_register(compiler, dst);
+
+    if (dst->reg.type == VKD3DSPR_OUTCONTROLPOINT)
+        compiler->use_vocp = true;
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_input_ps(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    vkd3d_dxbc_compiler_emit_input(compiler, &instruction->declaration.dst, VKD3D_SIV_NONE, instruction->flags);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_input_ps_sysval(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_register_semantic *semantic = &instruction->declaration.register_semantic;
+
+    vkd3d_dxbc_compiler_emit_input(compiler, &semantic->reg, semantic->sysval_semantic, instruction->flags);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_input_sysval(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    vkd3d_dxbc_compiler_emit_input(compiler, &instruction->declaration.register_semantic.reg,
+            instruction->declaration.register_semantic.sysval_semantic, VKD3DSIM_NONE);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_output(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst;
+
+    if (vkd3d_shader_register_is_output(&dst->reg))
+        vkd3d_dxbc_compiler_emit_output(compiler, dst, VKD3D_SIV_NONE);
+    else
+        vkd3d_dxbc_compiler_emit_output_register(compiler, dst);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_output_siv(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_shader_input_sysval_semantic sysval;
+    const struct vkd3d_shader_dst_param *dst;
+
+    dst = &instruction->declaration.register_semantic.reg;
+    sysval = instruction->declaration.register_semantic.sysval_semantic;
+
+    vkd3d_dxbc_compiler_emit_output(compiler, dst, sysval);
+}
+
+static bool vkd3d_dxbc_compiler_check_index_range(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_index_range *range)
+{
+    const struct vkd3d_shader_register *reg = &range->dst.reg;
+    struct vkd3d_shader_register_info reg_info;
+    struct vkd3d_shader_register current_reg;
+    struct vkd3d_symbol reg_symbol;
+    unsigned int i;
+    uint32_t id;
+
+    current_reg = *reg;
+    vkd3d_symbol_make_register(&reg_symbol, &current_reg);
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, &current_reg, &reg_info))
+    {
+        ERR("Failed to get register info.\n");
+        return false;
+    }
+
+    /* FIXME: We should check if it's an array. */
+    if (!reg_info.is_aggregate)
+    {
+        FIXME("Unhandled register %#x.\n", reg->type);
+        return false;
+    }
+    id = reg_info.id;
+
+    for (i = reg->idx[0].offset; i < reg->idx[0].offset + range->register_count; ++i)
+    {
+        current_reg.idx[0].offset = i;
+        vkd3d_symbol_make_register(&reg_symbol, &current_reg);
+
+        if (range->dst.write_mask != reg_info.write_mask
+                || vkd3d_write_mask_component_count(reg_info.write_mask) != 1)
+        {
+            FIXME("Unhandled index range write mask %#x (%#x).\n",
+                    range->dst.write_mask, reg_info.write_mask);
+            return false;
+        }
+
+        if (reg_info.id != id)
+        {
+            FIXME("Unhandled index range %#x, %u.\n", reg->type, i);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_index_range(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_index_range *range = &instruction->declaration.index_range;
+
+    if (!vkd3d_dxbc_compiler_check_index_range(compiler, range))
+        FIXME("Ignoring dcl_index_range %#x %u.\n", range->dst.reg.type, range->register_count);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_stream(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    unsigned int stream_idx = instruction->src[0].reg.idx[0].offset;
+
+    if (stream_idx)
+        FIXME("Multiple streams are not supported yet.\n");
+}
+
+static void vkd3d_dxbc_compiler_emit_output_vertex_count(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    vkd3d_dxbc_compiler_emit_execution_mode1(compiler,
+            SpvExecutionModeOutputVertices, instruction->declaration.count);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_input_primitive(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_primitive_type primitive_type = instruction->declaration.primitive_type.type;
+    SpvExecutionMode mode;
+
+    switch (primitive_type)
+    {
+        case VKD3D_PT_POINTLIST:
+            mode = SpvExecutionModeInputPoints;
+            break;
+        case VKD3D_PT_LINELIST:
+            mode = SpvExecutionModeInputLines;
+            break;
+        case VKD3D_PT_LINELIST_ADJ:
+            mode = SpvExecutionModeInputLinesAdjacency;
+            break;
+        case VKD3D_PT_TRIANGLELIST:
+            mode = SpvExecutionModeTriangles;
+            break;
+        case VKD3D_PT_TRIANGLELIST_ADJ:
+            mode = SpvExecutionModeInputTrianglesAdjacency;
+            break;
+        default:
+            FIXME("Unhandled primitive type %#x.\n", primitive_type);
+            return;
+    }
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, NULL, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_point_size(struct vkd3d_dxbc_compiler *compiler)
+{
+    static const struct vkd3d_spirv_builtin point_size = {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInPointSize};
+
+    /* Set the point size. Point sprites are not supported in d3d10+, but
+     * point primitives can still be used with e.g. stream output. Vulkan
+     * requires the point size to always be explicitly defined when outputting
+     * points. */
+    vkd3d_spirv_build_op_store(&compiler->spirv_builder,
+            vkd3d_dxbc_compiler_emit_builtin_variable(compiler, &point_size, SpvStorageClassOutput, 0),
+            vkd3d_dxbc_compiler_get_constant_float(compiler, 1.0f), SpvMemoryAccessMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_output_topology(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_primitive_type primitive_type = instruction->declaration.primitive_type.type;
+    SpvExecutionMode mode;
+
+    switch (primitive_type)
+    {
+        case VKD3D_PT_POINTLIST:
+            mode = SpvExecutionModeOutputPoints;
+            vkd3d_dxbc_compiler_emit_point_size(compiler);
+            break;
+        case VKD3D_PT_LINESTRIP:
+            mode = SpvExecutionModeOutputLineStrip;
+            break;
+        case VKD3D_PT_TRIANGLESTRIP:
+            mode = SpvExecutionModeOutputTriangleStrip;
+            break;
+        default:
+            ERR("Unexpected primitive type %#x.\n", primitive_type);
+            return;
+    }
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, NULL, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_gs_instances(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    compiler->spirv_builder.invocation_count = instruction->declaration.count;
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_tessellator_domain(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_tessellator_domain domain = instruction->declaration.tessellator_domain;
+    SpvExecutionMode mode;
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && vkd3d_dxbc_compiler_is_opengl_target(compiler))
+        return;
+
+    switch (domain)
+    {
+        case VKD3D_TESSELLATOR_DOMAIN_LINE:
+            mode = SpvExecutionModeIsolines;
+            break;
+        case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE:
+            mode = SpvExecutionModeTriangles;
+            break;
+        case VKD3D_TESSELLATOR_DOMAIN_QUAD:
+            mode = SpvExecutionModeQuads;
+            break;
+        default:
+            FIXME("Invalid tessellator domain %#x.\n", domain);
+            return;
+    }
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, NULL, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_tessellator_output_primitive(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_tessellator_output_primitive primitive)
+{
+    SpvExecutionMode mode;
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && vkd3d_dxbc_compiler_is_opengl_target(compiler))
+        return;
+
+    switch (primitive)
+    {
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT:
+            mode = SpvExecutionModePointMode;
+            break;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE:
+            return;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW:
+            mode = SpvExecutionModeVertexOrderCw;
+            break;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
+            mode = SpvExecutionModeVertexOrderCcw;
+            break;
+        default:
+            FIXME("Invalid tessellator output primitive %#x.\n", primitive);
+            return;
+    }
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, NULL, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_tessellator_partitioning(struct vkd3d_dxbc_compiler *compiler,
+        enum vkd3d_shader_tessellator_partitioning partitioning)
+{
+    SpvExecutionMode mode;
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && vkd3d_dxbc_compiler_is_opengl_target(compiler))
+        return;
+
+    switch (partitioning)
+    {
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER:
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2:
+            mode = SpvExecutionModeSpacingEqual;
+            break;
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
+            mode = SpvExecutionModeSpacingFractionalOdd;
+            break;
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
+            mode = SpvExecutionModeSpacingFractionalEven;
+            break;
+        default:
+            FIXME("Invalid tessellator partitioning %#x.\n", partitioning);
+            return;
+    }
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, NULL, 0);
+}
+
+static void vkd3d_dxbc_compiler_emit_dcl_thread_group(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_thread_group_size *group_size = &instruction->declaration.thread_group_size;
+    const uint32_t local_size[] = {group_size->x, group_size->y, group_size->z};
+
+    vkd3d_dxbc_compiler_emit_execution_mode(compiler,
+            SpvExecutionModeLocalSize, local_size, ARRAY_SIZE(local_size));
+}
+
+static void vkd3d_dxbc_compiler_leave_shader_phase(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_phase *phase)
+{
+    const struct vkd3d_shader_signature *signature = compiler->output_signature;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_symbol reg_symbol, *symbol;
+    struct vkd3d_shader_register reg;
+    struct rb_entry *entry;
+    unsigned int i;
+
+    vkd3d_spirv_build_op_function_end(builder);
+
+    if (compiler->epilogue_function_id)
+    {
+        vkd3d_dxbc_compiler_emit_shader_phase_name(compiler, compiler->epilogue_function_id, phase, "_epilogue");
+        vkd3d_dxbc_compiler_emit_shader_epilogue_function(compiler);
+    }
+
+    compiler->temp_id = 0;
+    compiler->temp_count = 0;
+
+    /*
+     * vocp inputs in fork and join shader phases are outputs of the control
+     * point phase. Reinsert symbols for vocp registers while leaving the
+     * control point phase.
+     */
+    if (is_control_point_phase(phase))
+    {
+        memset(&reg, 0, sizeof(reg));
+        reg.idx[1].offset = ~0u;
+
+        /* Fork and join phases share output registers (patch constants).
+         * Control point phase has separate output registers. */
+        memset(compiler->output_info, 0, signature->element_count * sizeof(*compiler->output_info));
+        memset(compiler->private_output_variable, 0, sizeof(compiler->private_output_variable));
+        memset(compiler->private_output_variable_array_idx, 0, sizeof(compiler->private_output_variable_array_idx));
+        memset(compiler->private_output_variable_write_mask, 0, sizeof(compiler->private_output_variable_write_mask));
+
+        for (i = 0; i < signature->element_count; ++i)
+        {
+            const struct vkd3d_shader_signature_element *e = &signature->elements[i];
+
+            reg.type = VKD3DSPR_OUTPUT;
+            reg.idx[0].offset = e->register_index;
+            vkd3d_symbol_make_register(&reg_symbol, &reg);
+            if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+            {
+                rb_remove(&compiler->symbol_table, entry);
+
+                symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+
+                reg.type = VKD3DSPR_OUTCONTROLPOINT;
+                reg.idx[1].offset = reg.idx[0].offset;
+                reg.idx[0].offset = compiler->output_control_point_count;
+                vkd3d_symbol_make_register(symbol, &reg);
+                symbol->info.reg.is_aggregate = false;
+
+                if (rb_put(&compiler->symbol_table, symbol, entry) == -1)
+                {
+                    ERR("Failed to insert vocp symbol entry (%s).\n", debug_vkd3d_symbol(symbol));
+                    vkd3d_symbol_free(entry, NULL);
+                }
+            }
+        }
+    }
+
+    if (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE)
+    {
+        signature = compiler->patch_constant_signature;
+
+        memset(&reg, 0, sizeof(reg));
+        reg.idx[1].offset = ~0u;
+
+        for (i = 0; i < signature->element_count; ++i)
+        {
+            const struct vkd3d_shader_signature_element *e = &signature->elements[i];
+
+            reg.type = VKD3DSPR_OUTPUT;
+            reg.idx[0].offset = e->register_index;
+            vkd3d_symbol_make_register(&reg_symbol, &reg);
+
+            if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+            {
+                rb_remove(&compiler->symbol_table, entry);
+                vkd3d_symbol_free(entry, NULL);
+            }
+        }
+    }
+
+    if (phase->instance_count)
+    {
+        reg.type = phase->type == VKD3DSIH_HS_FORK_PHASE ? VKD3DSPR_FORKINSTID : VKD3DSPR_JOININSTID;
+        reg.idx[0].offset = ~0u;
+        vkd3d_symbol_make_register(&reg_symbol, &reg);
+        if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
+        {
+            rb_remove(&compiler->symbol_table, entry);
+            vkd3d_symbol_free(entry, NULL);
+        }
+    }
+}
+
+static void vkd3d_dxbc_compiler_enter_shader_phase(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_phase *previous_phase;
+    struct vkd3d_shader_phase *phase;
+
+    if ((previous_phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler)))
+        vkd3d_dxbc_compiler_leave_shader_phase(compiler, previous_phase);
+
+    if (!vkd3d_array_reserve((void **)&compiler->shader_phases, &compiler->shader_phases_size,
+            compiler->shader_phase_count + 1, sizeof(*compiler->shader_phases)))
+        return;
+    phase = &compiler->shader_phases[compiler->shader_phase_count];
+
+    phase->type = instruction->handler_idx;
+    phase->idx = compiler->shader_phase_count;
+    phase->instance_count = 0;
+    phase->function_id = 0;
+    phase->instance_id = 0;
+    phase->function_location = 0;
+
+    ++compiler->shader_phase_count;
+}
+
+static int vkd3d_dxbc_compiler_emit_shader_phase_instance_count(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_shader_phase *phase = &compiler->shader_phases[compiler->shader_phase_count - 1];
+
+    if (!compiler->shader_phase_count
+            || (phase->type != VKD3DSIH_HS_FORK_PHASE && phase->type != VKD3DSIH_HS_JOIN_PHASE)
+            || phase->function_id)
+    {
+        WARN("Unexpected dcl_hs_{fork,join}_phase_instance_count instruction.\n");
+        return VKD3D_ERROR_INVALID_SHADER;
+    }
+
+    phase->instance_count = instruction->declaration.count;
+
+    vkd3d_dxbc_compiler_begin_shader_phase(compiler, phase);
+
+    return VKD3D_OK;
+}
+
+static const struct vkd3d_shader_phase *vkd3d_dxbc_compiler_get_control_point_phase(
+        struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_phase *phase;
+
+    if (compiler->shader_phase_count < 1)
+        return NULL;
+
+    phase = &compiler->shader_phases[0];
+    if (is_control_point_phase(phase))
+        return phase;
+
+    return NULL;
+}
+
+static void vkd3d_dxbc_compiler_emit_default_control_point_phase(struct vkd3d_dxbc_compiler *compiler)
+{
+    const struct vkd3d_shader_signature *output_signature = compiler->output_signature;
+    const struct vkd3d_shader_signature *input_signature = compiler->input_signature;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t type_id, input_ptr_type_id, output_ptr_type_id;
+    const struct vkd3d_spirv_builtin *input_builtin;
+    enum vkd3d_shader_component_type component_type;
+    uint32_t input_id, output_id, dst_id, src_id;
+    unsigned int component_count;
+    uint32_t invocation_id;
+    unsigned int i;
+
+    invocation_id = vkd3d_dxbc_compiler_emit_load_invocation_id(compiler);
+
+    assert(input_signature->element_count == output_signature->element_count);
+    for (i = 0; i < output_signature->element_count; ++i)
+    {
+        const struct vkd3d_shader_signature_element *output = &output_signature->elements[i];
+        const struct vkd3d_shader_signature_element *input = &input_signature->elements[i];
+
+        assert(input->mask == output->mask);
+        assert(input->component_type == output->component_type);
+
+        if ((input_builtin = get_spirv_builtin_for_sysval(compiler, vkd3d_siv_from_sysval(input->sysval_semantic))))
+        {
+            component_type = input_builtin->component_type;
+            component_count = input_builtin->component_count;
+        }
+        else
+        {
+            component_type = input->component_type;
+            component_count = vkd3d_write_mask_component_count(input->mask);
+        }
+
+        if (input_builtin)
+        {
+            input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler,
+                    input_builtin, SpvStorageClassInput, compiler->input_control_point_count);
+        }
+        else
+        {
+            input_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+                    SpvStorageClassInput, component_type, component_count, compiler->input_control_point_count);
+            vkd3d_spirv_add_iface_variable(builder, input_id);
+            vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, input->register_index);
+        }
+        vkd3d_spirv_build_op_name(builder, input_id, "vicp%u", input->register_index);
+
+        output_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+                SpvStorageClassOutput, component_type, component_count, compiler->output_control_point_count);
+        vkd3d_spirv_add_iface_variable(builder, output_id);
+        vkd3d_spirv_build_op_decorate1(builder, output_id, SpvDecorationLocation, output->register_index);
+        vkd3d_spirv_build_op_name(builder, output_id, "vocp%u", output->register_index);
+
+        type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+        output_ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
+        input_ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id);
+
+        dst_id = vkd3d_spirv_build_op_access_chain1(builder, output_ptr_type_id, output_id, invocation_id);
+        src_id = vkd3d_spirv_build_op_access_chain1(builder, input_ptr_type_id, input_id, invocation_id);
+        vkd3d_spirv_build_op_copy_memory(builder, dst_id, src_id, SpvMemoryAccessMaskNone);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_barrier(struct vkd3d_dxbc_compiler *compiler,
+        SpvScope execution_scope, SpvScope memory_scope, SpvMemorySemanticsMask semantics)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t execution_id, memory_id, semantics_id;
+
+    memory_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, memory_scope);
+    semantics_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, semantics);
+
+    if (execution_scope != SpvScopeMax)
+    {
+        execution_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, execution_scope);
+        vkd3d_spirv_build_op_control_barrier(builder, execution_id, memory_id, semantics_id);
+    }
+    else
+    {
+        vkd3d_spirv_build_op_memory_barrier(builder, memory_id, semantics_id);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_hull_shader_barrier(struct vkd3d_dxbc_compiler *compiler)
+{
+    vkd3d_dxbc_compiler_emit_barrier(compiler,
+            SpvScopeWorkgroup, SpvScopeInvocation, SpvMemorySemanticsMaskNone);
+}
+
+static void vkd3d_dxbc_compiler_emit_hull_shader_main(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_phase *control_point_phase, *phase;
+    uint32_t phase_instance_id;
+    unsigned int i, j;
+    uint32_t void_id;
+
+    vkd3d_spirv_builder_begin_main_function(builder);
+
+    void_id = vkd3d_spirv_get_op_type_void(builder);
+
+    if ((control_point_phase = vkd3d_dxbc_compiler_get_control_point_phase(compiler)))
+        vkd3d_spirv_build_op_function_call(builder, void_id, control_point_phase->function_id, NULL, 0);
+    else
+        vkd3d_dxbc_compiler_emit_default_control_point_phase(compiler);
+
+    if (compiler->use_vocp)
+        vkd3d_dxbc_compiler_emit_hull_shader_barrier(compiler);
+
+    for (i = 0; i < compiler->shader_phase_count; ++i)
+    {
+        phase = &compiler->shader_phases[i];
+        if (is_control_point_phase(phase))
+            continue;
+
+        if (phase->instance_count)
+        {
+            for (j = 0; j < phase->instance_count; ++j)
+            {
+                phase_instance_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, j);
+                vkd3d_spirv_build_op_function_call(builder,
+                        void_id, phase->function_id, &phase_instance_id, 1);
+            }
+        }
+        else
+        {
+            vkd3d_spirv_build_op_function_call(builder, void_id, phase->function_id, NULL, 0);
+        }
+    }
+
+    vkd3d_spirv_build_op_return(builder);
+    vkd3d_spirv_build_op_function_end(builder);
+}
+
+static SpvOp vkd3d_dxbc_compiler_map_alu_instruction(const struct vkd3d_shader_instruction *instruction)
+{
+    static const struct
+    {
+        enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+        SpvOp spirv_op;
+    }
+    alu_ops[] =
+    {
+        {VKD3DSIH_ADD,        SpvOpFAdd},
+        {VKD3DSIH_AND,        SpvOpBitwiseAnd},
+        {VKD3DSIH_BFREV,      SpvOpBitReverse},
+        {VKD3DSIH_COUNTBITS,  SpvOpBitCount},
+        {VKD3DSIH_DIV,        SpvOpFDiv},
+        {VKD3DSIH_FTOI,       SpvOpConvertFToS},
+        {VKD3DSIH_FTOU,       SpvOpConvertFToU},
+        {VKD3DSIH_IADD,       SpvOpIAdd},
+        {VKD3DSIH_INEG,       SpvOpSNegate},
+        {VKD3DSIH_ISHL,       SpvOpShiftLeftLogical},
+        {VKD3DSIH_ISHR,       SpvOpShiftRightArithmetic},
+        {VKD3DSIH_ITOF,       SpvOpConvertSToF},
+        {VKD3DSIH_MUL,        SpvOpFMul},
+        {VKD3DSIH_NOT,        SpvOpNot},
+        {VKD3DSIH_OR,         SpvOpBitwiseOr},
+        {VKD3DSIH_USHR,       SpvOpShiftRightLogical},
+        {VKD3DSIH_UTOF,       SpvOpConvertUToF},
+        {VKD3DSIH_XOR,        SpvOpBitwiseXor},
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(alu_ops); ++i)
+    {
+        if (alu_ops[i].handler_idx == instruction->handler_idx)
+            return alu_ops[i].spirv_op;
+    }
+
+    return SpvOpMax;
+}
+
+static void vkd3d_dxbc_compiler_emit_alu_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t src_ids[VKD3D_DXBC_MAX_SOURCE_COUNT];
+    uint32_t type_id, val_id;
+    unsigned int i;
+    SpvOp op;
+
+    op = vkd3d_dxbc_compiler_map_alu_instruction(instruction);
+    if (op == SpvOpMax)
+    {
+        ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+        return;
+    }
+
+    assert(instruction->dst_count == 1);
+    assert(instruction->src_count <= VKD3D_DXBC_MAX_SOURCE_COUNT);
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
+
+    for (i = 0; i < instruction->src_count; ++i)
+        src_ids[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], dst->write_mask);
+
+    val_id = vkd3d_spirv_build_op_trv(builder, &builder->function_stream, op, type_id,
+            src_ids, instruction->src_count);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static enum GLSLstd450 vkd3d_dxbc_compiler_map_ext_glsl_instruction(
+        const struct vkd3d_shader_instruction *instruction)
+{
+    static const struct
+    {
+        enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+        enum GLSLstd450 glsl_inst;
+    }
+    glsl_insts[] =
+    {
+        {VKD3DSIH_EXP,             GLSLstd450Exp2},
+        {VKD3DSIH_FIRSTBIT_HI,     GLSLstd450FindUMsb},
+        {VKD3DSIH_FIRSTBIT_LO,     GLSLstd450FindILsb},
+        {VKD3DSIH_FIRSTBIT_SHI,    GLSLstd450FindSMsb},
+        {VKD3DSIH_FRC,             GLSLstd450Fract},
+        {VKD3DSIH_IMAX,            GLSLstd450SMax},
+        {VKD3DSIH_IMIN,            GLSLstd450SMin},
+        {VKD3DSIH_LOG,             GLSLstd450Log2},
+        {VKD3DSIH_MAD,             GLSLstd450Fma},
+        {VKD3DSIH_MAX,             GLSLstd450NMax},
+        {VKD3DSIH_MIN,             GLSLstd450NMin},
+        {VKD3DSIH_ROUND_NE,        GLSLstd450RoundEven},
+        {VKD3DSIH_ROUND_NI,        GLSLstd450Floor},
+        {VKD3DSIH_ROUND_PI,        GLSLstd450Ceil},
+        {VKD3DSIH_ROUND_Z,         GLSLstd450Trunc},
+        {VKD3DSIH_RSQ,             GLSLstd450InverseSqrt},
+        {VKD3DSIH_SQRT,            GLSLstd450Sqrt},
+        {VKD3DSIH_UMAX,            GLSLstd450UMax},
+        {VKD3DSIH_UMIN,            GLSLstd450UMin},
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(glsl_insts); ++i)
+    {
+        if (glsl_insts[i].handler_idx == instruction->handler_idx)
+            return glsl_insts[i].glsl_inst;
+    }
+
+    return GLSLstd450Bad;
+}
+
+static void vkd3d_dxbc_compiler_emit_ext_glsl_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t src_id[VKD3D_DXBC_MAX_SOURCE_COUNT];
+    uint32_t instr_set_id, type_id, val_id;
+    enum GLSLstd450 glsl_inst;
+    unsigned int i;
+
+    glsl_inst = vkd3d_dxbc_compiler_map_ext_glsl_instruction(instruction);
+    if (glsl_inst == GLSLstd450Bad)
+    {
+        ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+        return;
+    }
+
+    instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+
+    assert(instruction->dst_count == 1);
+    assert(instruction->src_count <= VKD3D_DXBC_MAX_SOURCE_COUNT);
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
+
+    for (i = 0; i < instruction->src_count; ++i)
+        src_id[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], dst->write_mask);
+
+    val_id = vkd3d_spirv_build_op_ext_inst(builder, type_id,
+            instr_set_id, glsl_inst, src_id, instruction->src_count);
+
+    if (instruction->handler_idx == VKD3DSIH_FIRSTBIT_HI
+            || instruction->handler_idx == VKD3DSIH_FIRSTBIT_SHI)
+    {
+        /* In D3D bits are numbered from the most significant bit. */
+        val_id = vkd3d_spirv_build_op_isub(builder, type_id,
+                vkd3d_dxbc_compiler_get_constant_uint(compiler, 31), val_id);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_mov(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_register_info dst_reg_info, src_reg_info;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t val_id, dst_val_id, type_id, dst_id, src_id;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    unsigned int i, component_count;
+
+    if (src->reg.type == VKD3DSPR_IMMCONST || dst->modifiers || src->modifiers)
+        goto general_implementation;
+
+    vkd3d_dxbc_compiler_get_register_info(compiler, &dst->reg, &dst_reg_info);
+    vkd3d_dxbc_compiler_get_register_info(compiler, &src->reg, &src_reg_info);
+
+    if (dst_reg_info.component_type != src_reg_info.component_type
+            || dst_reg_info.write_mask != src_reg_info.write_mask)
+        goto general_implementation;
+
+    if (vkd3d_swizzle_is_equal(dst_reg_info.write_mask, src->swizzle, src_reg_info.write_mask))
+    {
+        dst_id = vkd3d_dxbc_compiler_get_register_id(compiler, &dst->reg);
+        src_id = vkd3d_dxbc_compiler_get_register_id(compiler, &src->reg);
+
+        vkd3d_spirv_build_op_copy_memory(builder, dst_id, src_id, SpvMemoryAccessMaskNone);
+        return;
+    }
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    if (component_count != 1 && component_count != VKD3D_VEC4_SIZE
+            && dst_reg_info.write_mask == VKD3DSP_WRITEMASK_ALL)
+    {
+        dst_id = vkd3d_dxbc_compiler_get_register_id(compiler, &dst->reg);
+        src_id = vkd3d_dxbc_compiler_get_register_id(compiler, &src->reg);
+
+        type_id = vkd3d_spirv_get_type_id(builder, dst_reg_info.component_type, VKD3D_VEC4_SIZE);
+        val_id = vkd3d_spirv_build_op_load(builder, type_id, src_id, SpvMemoryAccessMaskNone);
+        dst_val_id = vkd3d_spirv_build_op_load(builder, type_id, dst_id, SpvMemoryAccessMaskNone);
+
+        for (i = 0; i < ARRAY_SIZE(components); ++i)
+        {
+            if (dst->write_mask & (VKD3DSP_WRITEMASK_0 << i))
+                components[i] = VKD3D_VEC4_SIZE + vkd3d_swizzle_get_component(src->swizzle, i);
+            else
+                components[i] = i;
+        }
+
+        val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
+                type_id, dst_val_id, val_id, components, VKD3D_VEC4_SIZE);
+
+        vkd3d_spirv_build_op_store(builder, dst_id, val_id, SpvMemoryAccessMaskNone);
+        return;
+    }
+
+general_implementation:
+    val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst->write_mask);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_movc(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t condition_id, src1_id, src2_id, type_id, val_id;
+    unsigned int component_count;
+
+    condition_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst->write_mask);
+    src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
+    src2_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[2], dst->write_mask);
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
+
+    condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler,
+            VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id);
+    val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src1_id, src2_id);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_swapc(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t condition_id, src1_id, src2_id, type_id, val_id;
+    unsigned int component_count;
+
+    assert(dst[0].write_mask == dst[1].write_mask);
+
+    condition_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst->write_mask);
+    src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
+    src2_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[2], dst->write_mask);
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
+
+    condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler,
+            VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id);
+
+    val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src2_id, src1_id);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, &dst[0], val_id);
+    val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src1_id, src2_id);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, &dst[1], val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_dot(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    enum vkd3d_shader_component_type component_type;
+    uint32_t type_id, val_id, src_ids[2];
+    unsigned int component_count, i;
+    DWORD write_mask;
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    component_type = vkd3d_component_type_from_data_type(dst->reg.data_type);
+
+    if (instruction->handler_idx == VKD3DSIH_DP4)
+        write_mask = VKD3DSP_WRITEMASK_ALL;
+    else if (instruction->handler_idx == VKD3DSIH_DP3)
+        write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_2;
+    else
+        write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1;
+
+    assert(instruction->src_count == ARRAY_SIZE(src_ids));
+    for (i = 0; i < ARRAY_SIZE(src_ids); ++i)
+        src_ids[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], write_mask);
+
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+
+    val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            SpvOpDot, type_id, src_ids[0], src_ids[1]);
+    if (component_count > 1)
+    {
+        val_id = vkd3d_dxbc_compiler_emit_construct_vector(compiler,
+                component_type, component_count, val_id, 0, 1);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_rcp(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, src_id, val_id;
+    unsigned int component_count;
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
+
+    src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst->write_mask);
+    val_id = vkd3d_spirv_build_op_fdiv(builder, type_id,
+            vkd3d_dxbc_compiler_get_constant_float_vector(compiler, 1.0f, component_count), src_id);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_sincos(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_dst_param *dst_sin = &instruction->dst[0];
+    const struct vkd3d_shader_dst_param *dst_cos = &instruction->dst[1];
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, src_id, sin_id = 0, cos_id = 0;
+
+    if (dst_sin->reg.type != VKD3DSPR_NULL)
+    {
+        type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst_sin);
+        src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst_sin->write_mask);
+
+        sin_id = vkd3d_spirv_build_op_glsl_std450_sin(builder, type_id, src_id);
+    }
+
+    if (dst_cos->reg.type != VKD3DSPR_NULL)
+    {
+        if (dst_sin->reg.type == VKD3DSPR_NULL || dst_cos->write_mask != dst_sin->write_mask)
+        {
+            type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst_cos);
+            src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst_cos->write_mask);
+        }
+
+        cos_id = vkd3d_spirv_build_op_glsl_std450_cos(builder, type_id, src_id);
+    }
+
+    if (sin_id)
+        vkd3d_dxbc_compiler_emit_store_dst(compiler, dst_sin, sin_id);
+
+    if (cos_id)
+        vkd3d_dxbc_compiler_emit_store_dst(compiler, dst_cos, cos_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_imul(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, val_id, src0_id, src1_id;
+
+    if (dst[0].reg.type != VKD3DSPR_NULL)
+        FIXME("Extended multiplies not implemented.\n"); /* SpvOpSMulExtended */
+
+    if (dst[1].reg.type == VKD3DSPR_NULL)
+        return;
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[1]);
+
+    src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[1].write_mask);
+    src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[1].write_mask);
+
+    val_id = vkd3d_spirv_build_op_imul(builder, type_id, src0_id, src1_id);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, &dst[1], val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_imad(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, val_id, src_ids[3];
+    unsigned int i, component_count;
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, component_count);
+
+    for (i = 0; i < ARRAY_SIZE(src_ids); ++i)
+        src_ids[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], dst->write_mask);
+
+    val_id = vkd3d_spirv_build_op_imul(builder, type_id, src_ids[0], src_ids[1]);
+    val_id = vkd3d_spirv_build_op_iadd(builder, type_id, val_id, src_ids[2]);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_udiv(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t type_id, val_id, src0_id, src1_id, condition_id, uint_max_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    unsigned int component_count = 0;
+
+    if (dst[0].reg.type != VKD3DSPR_NULL)
+    {
+        component_count = vkd3d_write_mask_component_count(dst[0].write_mask);
+        type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[0]);
+
+        src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[0].write_mask);
+        src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[0].write_mask);
+
+        condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler,
+                VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, src1_id);
+        uint_max_id = vkd3d_dxbc_compiler_get_constant_uint_vector(compiler,
+                0xffffffff, component_count);
+
+        val_id = vkd3d_spirv_build_op_udiv(builder, type_id, src0_id, src1_id);
+        /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */
+        val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id);
+
+        vkd3d_dxbc_compiler_emit_store_dst(compiler, &dst[0], val_id);
+    }
+
+    if (dst[1].reg.type != VKD3DSPR_NULL)
+    {
+        if (!component_count || dst[0].write_mask != dst[1].write_mask)
+        {
+            component_count = vkd3d_write_mask_component_count(dst[1].write_mask);
+            type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[1]);
+
+            src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[1].write_mask);
+            src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[1].write_mask);
+
+            condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler,
+                    VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, src1_id);
+            uint_max_id = vkd3d_dxbc_compiler_get_constant_uint_vector(compiler,
+                    0xffffffff, component_count);
+        }
+
+        val_id = vkd3d_spirv_build_op_umod(builder, type_id, src0_id, src1_id);
+        /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */
+        val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id);
+
+        vkd3d_dxbc_compiler_emit_store_dst(compiler, &dst[1], val_id);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_bitfield_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t src_ids[4], constituents[VKD3D_VEC4_SIZE], type_id, mask_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    enum vkd3d_shader_component_type component_type;
+    unsigned int i, j, k, src_count;
+    DWORD write_mask;
+    SpvOp op;
+
+    src_count = instruction->src_count;
+    assert(2 <= src_count && src_count <= ARRAY_SIZE(src_ids));
+
+    component_type = vkd3d_component_type_from_data_type(dst->reg.data_type);
+    type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+    mask_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0x1f);
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_BFI:  op = SpvOpBitFieldInsert; break;
+        case VKD3DSIH_IBFE: op = SpvOpBitFieldSExtract; break;
+        case VKD3DSIH_UBFE: op = SpvOpBitFieldUExtract; break;
+        default:
+            ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+            return;
+    }
+
+    assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+    for (i = 0, k = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (!(write_mask = dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        for (j = 0; j < src_count; ++j)
+        {
+            src_ids[src_count - j - 1] = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler,
+                    &src[j], write_mask, component_type);
+        }
+
+        /* In SPIR-V, the last two operands are Offset and Count. */
+        for (j = src_count - 2; j < src_count; ++j)
+        {
+            src_ids[j] = vkd3d_spirv_build_op_and(builder, type_id, src_ids[j], mask_id);
+        }
+
+        constituents[k++] = vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
+                op, type_id, src_ids, src_count);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler, dst, component_type, constituents);
+}
+
+static void vkd3d_dxbc_compiler_emit_f16tof32(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t instr_set_id, type_id, scalar_type_id, src_id, result_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    unsigned int i, j;
+    DWORD write_mask;
+
+    instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
+    scalar_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 1);
+
+    /* FIXME: Consider a single UnpackHalf2x16 intruction per 2 components. */
+    assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+    for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (!(write_mask = dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, write_mask);
+        result_id = vkd3d_spirv_build_op_ext_inst(builder, type_id,
+                instr_set_id, GLSLstd450UnpackHalf2x16, &src_id, 1);
+        components[j++] = vkd3d_spirv_build_op_composite_extract1(builder,
+                scalar_type_id, result_id, 0);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler,
+            dst, vkd3d_component_type_from_data_type(dst->reg.data_type), components);
+}
+
+static void vkd3d_dxbc_compiler_emit_f32tof16(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t instr_set_id, type_id, scalar_type_id, src_id, zero_id, constituents[2];
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t components[VKD3D_VEC4_SIZE];
+    unsigned int i, j;
+    DWORD write_mask;
+
+    instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
+    scalar_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    zero_id = vkd3d_dxbc_compiler_get_constant_float(compiler, 0.0f);
+
+    /* FIXME: Consider a single PackHalf2x16 intruction per 2 components. */
+    assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+    for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (!(write_mask = dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, write_mask);
+        constituents[0] = src_id;
+        constituents[1] = zero_id;
+        src_id = vkd3d_spirv_build_op_composite_construct(builder,
+                type_id, constituents, ARRAY_SIZE(constituents));
+        components[j++] = vkd3d_spirv_build_op_ext_inst(builder, scalar_type_id,
+                instr_set_id, GLSLstd450PackHalf2x16, &src_id, 1);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler,
+            dst, vkd3d_component_type_from_data_type(dst->reg.data_type), components);
+}
+
+static void vkd3d_dxbc_compiler_emit_comparison_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t src0_id, src1_id, type_id, result_id;
+    unsigned int component_count;
+    SpvOp op;
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_EQ:  op = SpvOpFOrdEqual; break;
+        case VKD3DSIH_GE:  op = SpvOpFOrdGreaterThanEqual; break;
+        case VKD3DSIH_IEQ: op = SpvOpIEqual; break;
+        case VKD3DSIH_IGE: op = SpvOpSGreaterThanEqual; break;
+        case VKD3DSIH_ILT: op = SpvOpSLessThan; break;
+        case VKD3DSIH_INE: op = SpvOpINotEqual; break;
+        case VKD3DSIH_LT:  op = SpvOpFOrdLessThan; break;
+        case VKD3DSIH_NE:  op = SpvOpFUnordNotEqual; break;
+        case VKD3DSIH_UGE: op = SpvOpUGreaterThanEqual; break;
+        case VKD3DSIH_ULT: op = SpvOpULessThan; break;
+        default:
+            ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+            return;
+    }
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+
+    src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst->write_mask);
+    src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count);
+    result_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+            op, type_id, src0_id, src1_id);
+
+    result_id = vkd3d_dxbc_compiler_emit_bool_to_int(compiler, component_count, result_id);
+    vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, result_id);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_conditional_branch(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction, uint32_t target_block_id)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t condition_id, merge_block_id;
+
+    condition_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
+    condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler, instruction->flags, 1, condition_id);
+
+    merge_block_id = vkd3d_spirv_alloc_id(builder);
+
+    vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
+    vkd3d_spirv_build_op_branch_conditional(builder, condition_id, target_block_id, merge_block_id);
+
+    return merge_block_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_shader_epilogue_invocation(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t void_id, type_id, ptr_type_id, function_id;
+    uint32_t arguments[MAX_REG_OUTPUT];
+    unsigned int i, count;
+
+    if ((function_id = compiler->epilogue_function_id))
+    {
+        void_id = vkd3d_spirv_get_op_type_void(builder);
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
+        for (i = 0, count = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
+        {
+            if (compiler->private_output_variable[i])
+            {
+                uint32_t argument_id = compiler->private_output_variable[i];
+                unsigned int argument_idx = count++;
+
+                if (compiler->private_output_variable_array_idx[i])
+                {
+                    uint32_t tmp_id;
+
+                    tmp_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id,
+                            argument_id, compiler->private_output_variable_array_idx[i]);
+                    tmp_id = vkd3d_spirv_build_op_load(builder, type_id, tmp_id, SpvMemoryAccessMaskNone);
+                    argument_id = vkd3d_spirv_build_op_variable(builder,
+                            &builder->global_stream, ptr_type_id, SpvStorageClassPrivate, 0);
+                    vkd3d_spirv_build_op_store(builder, argument_id, tmp_id, SpvMemoryAccessMaskNone);
+                }
+
+                arguments[argument_idx] = argument_id;
+            }
+        }
+
+        vkd3d_spirv_build_op_function_call(builder, void_id, function_id, arguments, count);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_return(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY)
+        vkd3d_dxbc_compiler_emit_shader_epilogue_invocation(compiler);
+
+    vkd3d_spirv_build_op_return(builder);
+}
+
+static void vkd3d_dxbc_compiler_emit_retc(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t target_id, merge_block_id;
+
+    target_id = vkd3d_spirv_alloc_id(builder);
+    merge_block_id = vkd3d_dxbc_compiler_emit_conditional_branch(compiler, instruction, target_id);
+
+    vkd3d_spirv_build_op_label(builder, target_id);
+    vkd3d_dxbc_compiler_emit_return(compiler, instruction);
+    vkd3d_spirv_build_op_label(builder, merge_block_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_kill(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t target_id, merge_block_id;
+
+    target_id = vkd3d_spirv_alloc_id(builder);
+    merge_block_id = vkd3d_dxbc_compiler_emit_conditional_branch(compiler, instruction, target_id);
+
+    vkd3d_spirv_build_op_label(builder, target_id);
+
+    if (vkd3d_dxbc_compiler_is_target_extension_supported(compiler,
+            VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION))
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityDemoteToHelperInvocationEXT);
+        vkd3d_spirv_build_op_demote_to_helper_invocation(builder);
+        vkd3d_spirv_build_op_branch(builder, merge_block_id);
+    }
+    else
+    {
+        vkd3d_spirv_build_op_kill(builder);
+    }
+
+    vkd3d_spirv_build_op_label(builder, merge_block_id);
+}
+
+static struct vkd3d_control_flow_info *vkd3d_dxbc_compiler_push_control_flow_level(
+        struct vkd3d_dxbc_compiler *compiler)
+{
+    if (!vkd3d_array_reserve((void **)&compiler->control_flow_info, &compiler->control_flow_info_size,
+            compiler->control_flow_depth + 1, sizeof(*compiler->control_flow_info)))
+    {
+        ERR("Failed to allocate control flow info structure.\n");
+        return NULL;
+    }
+
+    return &compiler->control_flow_info[compiler->control_flow_depth++];
+}
+
+static void vkd3d_dxbc_compiler_pop_control_flow_level(struct vkd3d_dxbc_compiler *compiler)
+{
+    struct vkd3d_control_flow_info *cf_info;
+
+    assert(compiler->control_flow_depth);
+
+    cf_info = &compiler->control_flow_info[--compiler->control_flow_depth];
+    memset(cf_info, 0, sizeof(*cf_info));
+}
+
+static struct vkd3d_control_flow_info *vkd3d_dxbc_compiler_find_innermost_loop(
+        struct vkd3d_dxbc_compiler *compiler)
+{
+    int depth;
+
+    for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
+    {
+        if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP)
+            return &compiler->control_flow_info[depth];
+    }
+
+    return NULL;
+}
+
+static struct vkd3d_control_flow_info *vkd3d_dxbc_compiler_find_innermost_breakable_cf_construct(
+        struct vkd3d_dxbc_compiler *compiler)
+{
+    int depth;
+
+    for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
+    {
+        if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP
+                || compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
+            return &compiler->control_flow_info[depth];
+    }
+
+    return NULL;
+}
+
+static int vkd3d_dxbc_compiler_emit_control_flow_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t loop_header_block_id, loop_body_block_id, continue_block_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t merge_block_id, val_id, condition_id, true_label;
+    struct vkd3d_control_flow_info *cf_info;
+
+    cf_info = compiler->control_flow_depth
+            ? &compiler->control_flow_info[compiler->control_flow_depth - 1] : NULL;
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_IF:
+            if (!(cf_info = vkd3d_dxbc_compiler_push_control_flow_level(compiler)))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+
+            val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
+            condition_id = vkd3d_dxbc_compiler_emit_int_to_bool(compiler, instruction->flags, 1, val_id);
+
+            true_label = vkd3d_spirv_alloc_id(builder);
+            merge_block_id = vkd3d_spirv_alloc_id(builder);
+            vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
+            cf_info->u.if_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+            vkd3d_spirv_build_op_branch_conditional(builder, condition_id, true_label, merge_block_id);
+
+            vkd3d_spirv_build_op_label(builder, true_label);
+
+            cf_info->u.if_.id = compiler->branch_id;
+            cf_info->u.if_.merge_block_id = merge_block_id;
+            cf_info->u.if_.else_block_id = 0;
+            cf_info->inside_block = true;
+            cf_info->current_block = VKD3D_BLOCK_IF;
+
+            vkd3d_spirv_build_op_name(builder, merge_block_id, "branch%u_merge", compiler->branch_id);
+            vkd3d_spirv_build_op_name(builder, true_label, "branch%u_true", compiler->branch_id);
+            ++compiler->branch_id;
+            break;
+
+        case VKD3DSIH_ELSE:
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_IF);
+
+            if (cf_info->inside_block)
+                vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
+
+            cf_info->u.if_.else_block_id = vkd3d_spirv_alloc_id(builder);
+            vkd3d_spirv_as_op_branch_conditional(&builder->function_stream,
+                    cf_info->u.if_.stream_location)->false_label = cf_info->u.if_.else_block_id;
+            vkd3d_spirv_build_op_name(builder,
+                    cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id);
+            vkd3d_spirv_build_op_label(builder, cf_info->u.if_.else_block_id);
+            cf_info->inside_block = true;
+            break;
+
+        case VKD3DSIH_ENDIF:
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_IF);
+
+            if (cf_info->inside_block)
+                vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
+
+            vkd3d_spirv_build_op_label(builder, cf_info->u.if_.merge_block_id);
+
+            vkd3d_dxbc_compiler_pop_control_flow_level(compiler);
+            break;
+
+        case VKD3DSIH_LOOP:
+            if (!(cf_info = vkd3d_dxbc_compiler_push_control_flow_level(compiler)))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+
+            loop_header_block_id = vkd3d_spirv_alloc_id(builder);
+            loop_body_block_id = vkd3d_spirv_alloc_id(builder);
+            continue_block_id = vkd3d_spirv_alloc_id(builder);
+            merge_block_id = vkd3d_spirv_alloc_id(builder);
+
+            vkd3d_spirv_build_op_branch(builder, loop_header_block_id);
+            vkd3d_spirv_build_op_label(builder, loop_header_block_id);
+            vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone);
+            vkd3d_spirv_build_op_branch(builder, loop_body_block_id);
+
+            vkd3d_spirv_build_op_label(builder, loop_body_block_id);
+
+            cf_info->u.loop.header_block_id = loop_header_block_id;
+            cf_info->u.loop.continue_block_id = continue_block_id;
+            cf_info->u.loop.merge_block_id = merge_block_id;
+            cf_info->current_block = VKD3D_BLOCK_LOOP;
+
+            vkd3d_spirv_build_op_name(builder, loop_header_block_id, "loop%u_header", compiler->loop_id);
+            vkd3d_spirv_build_op_name(builder, loop_body_block_id, "loop%u_body", compiler->loop_id);
+            vkd3d_spirv_build_op_name(builder, continue_block_id, "loop%u_continue", compiler->loop_id);
+            vkd3d_spirv_build_op_name(builder, merge_block_id, "loop%u_merge", compiler->loop_id);
+            ++compiler->loop_id;
+            break;
+
+        case VKD3DSIH_ENDLOOP:
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_LOOP);
+
+            vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.continue_block_id);
+
+            vkd3d_spirv_build_op_label(builder, cf_info->u.loop.continue_block_id);
+            vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.header_block_id);
+            vkd3d_spirv_build_op_label(builder, cf_info->u.loop.merge_block_id);
+
+            vkd3d_dxbc_compiler_pop_control_flow_level(compiler);
+            break;
+
+        case VKD3DSIH_SWITCH:
+            if (!(cf_info = vkd3d_dxbc_compiler_push_control_flow_level(compiler)))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+
+            merge_block_id = vkd3d_spirv_alloc_id(builder);
+
+            assert(src->reg.data_type == VKD3D_DATA_INT);
+            val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
+
+            vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
+
+            cf_info->u.switch_.id = compiler->switch_id;
+            cf_info->u.switch_.merge_block_id = merge_block_id;
+            cf_info->u.switch_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+            cf_info->u.switch_.selector_id = val_id;
+            cf_info->u.switch_.case_blocks = NULL;
+            cf_info->u.switch_.case_blocks_size = 0;
+            cf_info->u.switch_.case_block_count = 0;
+            cf_info->u.switch_.default_block_id = 0;
+            cf_info->inside_block = false;
+            cf_info->current_block = VKD3D_BLOCK_SWITCH;
+
+            vkd3d_spirv_build_op_name(builder, merge_block_id, "switch%u_merge", compiler->switch_id);
+
+            ++compiler->switch_id;
+
+            if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size,
+                    10, sizeof(*cf_info->u.switch_.case_blocks)))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+
+            break;
+
+        case VKD3DSIH_ENDSWITCH:
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
+            assert(!cf_info->inside_block);
+
+            if (!cf_info->u.switch_.default_block_id)
+                cf_info->u.switch_.default_block_id = cf_info->u.switch_.merge_block_id;
+
+            vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.merge_block_id);
+
+            /* The OpSwitch instruction is inserted when the endswitch
+             * instruction is processed because we do not know the number
+             * of case statments in advance.*/
+            vkd3d_spirv_begin_function_stream_insertion(builder, cf_info->u.switch_.stream_location);
+            vkd3d_spirv_build_op_switch(builder, cf_info->u.switch_.selector_id,
+                    cf_info->u.switch_.default_block_id, cf_info->u.switch_.case_blocks,
+                    cf_info->u.switch_.case_block_count);
+            vkd3d_spirv_end_function_stream_insertion(builder);
+
+            vkd3d_free(cf_info->u.switch_.case_blocks);
+            vkd3d_dxbc_compiler_pop_control_flow_level(compiler);
+            break;
+
+        case VKD3DSIH_CASE:
+        {
+            uint32_t label_id, value;
+
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
+
+            assert(src->swizzle == VKD3D_SHADER_NO_SWIZZLE && src->reg.type == VKD3DSPR_IMMCONST);
+            value = *src->reg.u.immconst_uint;
+
+            if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size,
+                    2 * (cf_info->u.switch_.case_block_count + 1), sizeof(*cf_info->u.switch_.case_blocks)))
+                return VKD3D_ERROR_OUT_OF_MEMORY;
+
+            label_id = vkd3d_spirv_alloc_id(builder);
+            if (cf_info->inside_block) /* fall-through */
+                vkd3d_spirv_build_op_branch(builder, label_id);
+
+            cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 0] = value;
+            cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 1] = label_id;
+            ++cf_info->u.switch_.case_block_count;
+
+            vkd3d_spirv_build_op_label(builder, label_id);
+            cf_info->inside_block = true;
+            vkd3d_spirv_build_op_name(builder, label_id, "switch%u_case%u", cf_info->u.switch_.id, value);
+            break;
+        }
+
+        case VKD3DSIH_DEFAULT:
+            assert(compiler->control_flow_depth);
+            assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
+            assert(!cf_info->u.switch_.default_block_id);
+
+            cf_info->u.switch_.default_block_id = vkd3d_spirv_alloc_id(builder);
+            if (cf_info->inside_block) /* fall-through */
+                vkd3d_spirv_build_op_branch(builder, cf_info->u.switch_.default_block_id);
+
+            vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.default_block_id);
+            vkd3d_spirv_build_op_name(builder, cf_info->u.switch_.default_block_id,
+                    "switch%u_default", cf_info->u.switch_.id);
+            cf_info->inside_block = true;
+            break;
+
+        case VKD3DSIH_BREAK:
+        {
+            struct vkd3d_control_flow_info *breakable_cf_info;
+
+            assert(compiler->control_flow_depth);
+
+            if (!(breakable_cf_info = vkd3d_dxbc_compiler_find_innermost_breakable_cf_construct(compiler)))
+            {
+                FIXME("Unhandled break instruction.\n");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+
+            if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
+            {
+                vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.loop.merge_block_id);
+            }
+            else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
+            {
+                assert(breakable_cf_info->inside_block);
+                vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.switch_.merge_block_id);
+            }
+
+            cf_info->inside_block = false;
+            break;
+        }
+
+        case VKD3DSIH_BREAKP:
+        {
+            struct vkd3d_control_flow_info *loop_cf_info;
+
+            assert(compiler->control_flow_depth);
+
+            if (!(loop_cf_info = vkd3d_dxbc_compiler_find_innermost_loop(compiler)))
+            {
+                ERR("Invalid 'breakc' instruction outside loop.\n");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+
+            merge_block_id = vkd3d_dxbc_compiler_emit_conditional_branch(compiler,
+                    instruction, loop_cf_info->u.loop.merge_block_id);
+            vkd3d_spirv_build_op_label(builder, merge_block_id);
+            break;
+        }
+
+        case VKD3DSIH_CONTINUE:
+        {
+            struct vkd3d_control_flow_info *loop_cf_info;
+
+            assert(compiler->control_flow_depth);
+
+            if (!(loop_cf_info = vkd3d_dxbc_compiler_find_innermost_loop(compiler)))
+            {
+                ERR("Invalid 'continue' instruction outside loop.\n");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+
+            vkd3d_spirv_build_op_branch(builder, loop_cf_info->u.loop.continue_block_id);
+
+            cf_info->inside_block = false;
+            break;
+        }
+
+        case VKD3DSIH_CONTINUEP:
+        {
+            struct vkd3d_control_flow_info *loop_cf_info;
+
+            if (!(loop_cf_info = vkd3d_dxbc_compiler_find_innermost_loop(compiler)))
+            {
+                ERR("Invalid 'continuec' instruction outside loop.\n");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+
+            merge_block_id = vkd3d_dxbc_compiler_emit_conditional_branch(compiler,
+                    instruction, loop_cf_info->u.loop.continue_block_id);
+            vkd3d_spirv_build_op_label(builder, merge_block_id);
+            break;
+        }
+
+        case VKD3DSIH_RET:
+            vkd3d_dxbc_compiler_emit_return(compiler, instruction);
+
+            if (cf_info)
+                cf_info->inside_block = false;
+            break;
+
+        case VKD3DSIH_RETP:
+            vkd3d_dxbc_compiler_emit_retc(compiler, instruction);
+            break;
+
+        case VKD3DSIH_TEXKILL:
+            vkd3d_dxbc_compiler_emit_kill(compiler, instruction);
+            break;
+
+        default:
+            ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+            break;
+    }
+
+    return VKD3D_OK;
+}
+
+static void vkd3d_dxbc_compiler_emit_deriv_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct instruction_info *info;
+    uint32_t type_id, src_id, val_id;
+    unsigned int i;
+
+    static const struct instruction_info
+    {
+        enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+        SpvOp op;
+        bool needs_derivative_control;
+    }
+    deriv_instructions[] =
+    {
+        {VKD3DSIH_DSX,        SpvOpDPdx},
+        {VKD3DSIH_DSX_COARSE, SpvOpDPdxCoarse, true},
+        {VKD3DSIH_DSX_FINE,   SpvOpDPdxFine,   true},
+        {VKD3DSIH_DSY,        SpvOpDPdy},
+        {VKD3DSIH_DSY_COARSE, SpvOpDPdyCoarse, true},
+        {VKD3DSIH_DSY_FINE,   SpvOpDPdyFine,   true},
+    };
+
+    info = NULL;
+    for (i = 0; i < ARRAY_SIZE(deriv_instructions); ++i)
+    {
+        if (deriv_instructions[i].handler_idx == instruction->handler_idx)
+        {
+            info = &deriv_instructions[i];
+            break;
+        }
+    }
+    if (!info)
+    {
+        ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+        return;
+    }
+
+    if (info->needs_derivative_control)
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityDerivativeControl);
+
+    assert(instruction->dst_count == 1);
+    assert(instruction->src_count == 1);
+
+    type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
+    src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst->write_mask);
+    val_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, info->op, type_id, src_id);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+struct vkd3d_shader_image
+{
+    uint32_t id;
+    uint32_t image_id;
+    uint32_t sampled_image_id;
+
+    enum vkd3d_shader_component_type sampled_type;
+    uint32_t image_type_id;
+    const struct vkd3d_spirv_resource_type *resource_type_info;
+    unsigned int structure_stride;
+    bool raw;
+};
+
+#define VKD3D_IMAGE_FLAG_NONE    0x0
+#define VKD3D_IMAGE_FLAG_DEPTH   0x1
+#define VKD3D_IMAGE_FLAG_NO_LOAD 0x2
+#define VKD3D_IMAGE_FLAG_SAMPLED 0x4
+
+static const struct vkd3d_symbol *vkd3d_dxbc_compiler_find_resource(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *resource_reg)
+{
+    struct vkd3d_symbol resource_key;
+    struct rb_entry *entry;
+
+    vkd3d_symbol_make_resource(&resource_key, resource_reg);
+    entry = rb_get(&compiler->symbol_table, &resource_key);
+    assert(entry);
+    return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+}
+
+static const struct vkd3d_symbol *vkd3d_dxbc_compiler_find_combined_sampler(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *resource_reg, const struct vkd3d_shader_register *sampler_reg)
+{
+    const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
+    unsigned int sampler_space, sampler_index;
+    struct vkd3d_symbol key;
+    struct rb_entry *entry;
+
+    if (!shader_interface->combined_sampler_count)
+        return NULL;
+
+    if (sampler_reg)
+    {
+        const struct vkd3d_symbol *sampler_symbol;
+
+        vkd3d_symbol_make_sampler(&key, sampler_reg);
+        if (!(entry = rb_get(&compiler->symbol_table, &key)))
+            return NULL;
+        sampler_symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+        sampler_space = sampler_symbol->info.sampler.register_space;
+        sampler_index = sampler_symbol->info.sampler.register_index;
+    }
+    else
+    {
+        sampler_space = 0;
+        sampler_index = VKD3D_SHADER_DUMMY_SAMPLER_INDEX;
+    }
+
+    vkd3d_symbol_make_combined_sampler(&key, resource_reg, sampler_space, sampler_index);
+    if ((entry = rb_get(&compiler->symbol_table, &key)))
+        return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+    return NULL;
+}
+
+static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compiler,
+        struct vkd3d_shader_image *image, const struct vkd3d_shader_register *resource_reg,
+        const struct vkd3d_shader_register *sampler_reg, unsigned int flags)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t sampler_var_id, sampler_id, sampled_image_type_id;
+    const struct vkd3d_symbol *symbol = NULL;
+    bool load, sampled, depth_comparison;
+
+    load = !(flags & VKD3D_IMAGE_FLAG_NO_LOAD);
+    sampled = flags & VKD3D_IMAGE_FLAG_SAMPLED;
+    depth_comparison = flags & VKD3D_IMAGE_FLAG_DEPTH;
+
+    if (resource_reg->type == VKD3DSPR_RESOURCE)
+        symbol = vkd3d_dxbc_compiler_find_combined_sampler(compiler, resource_reg, sampler_reg);
+    if (!symbol)
+        symbol = vkd3d_dxbc_compiler_find_resource(compiler, resource_reg);
+
+    image->id = symbol->id;
+    image->sampled_type = symbol->info.resource.sampled_type;
+    image->image_type_id = symbol->info.resource.type_id;
+    image->resource_type_info = symbol->info.resource.resource_type_info;
+    image->structure_stride = symbol->info.resource.structure_stride;
+    image->raw = symbol->info.resource.raw;
+
+    if (symbol->type == VKD3D_SYMBOL_COMBINED_SAMPLER)
+    {
+        sampled_image_type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image->image_type_id);
+        image->sampled_image_id = vkd3d_spirv_build_op_load(builder,
+                sampled_image_type_id, image->id, SpvMemoryAccessMaskNone);
+        image->image_id = !sampled ? vkd3d_spirv_build_op_image(builder,
+                image->image_type_id, image->sampled_image_id) : 0;
+        return;
+    }
+
+    image->image_id = load ? vkd3d_spirv_build_op_load(builder,
+            image->image_type_id, image->id, SpvMemoryAccessMaskNone) : 0;
+
+    image->image_type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, resource_reg,
+            symbol->info.resource.register_space, symbol->info.resource.register_index, image->resource_type_info,
+            image->sampled_type, image->structure_stride || image->raw, depth_comparison);
+
+    if (sampled)
+    {
+        assert(image->image_id);
+        assert(sampler_reg);
+
+        sampler_var_id = vkd3d_dxbc_compiler_get_register_id(compiler, sampler_reg);
+
+        sampler_id = vkd3d_spirv_build_op_load(builder,
+                vkd3d_spirv_get_op_type_sampler(builder), sampler_var_id, SpvMemoryAccessMaskNone);
+        sampled_image_type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image->image_type_id);
+        image->sampled_image_id = vkd3d_spirv_build_op_sampled_image(builder,
+                sampled_image_type_id, image->image_id, sampler_id);
+    }
+    else
+    {
+        image->sampled_image_id = 0;
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_texel_offset(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction,
+        const struct vkd3d_spirv_resource_type *resource_type_info)
+{
+    const struct vkd3d_shader_texel_offset *offset = &instruction->texel_offset;
+    unsigned int component_count = resource_type_info->offset_component_count;
+    int32_t data[4] = {offset->u, offset->v, offset->w, 0};
+    return vkd3d_dxbc_compiler_get_constant(compiler,
+            VKD3D_SHADER_COMPONENT_INT, component_count, (const uint32_t *)data);
+}
+
+static void vkd3d_dxbc_compiler_emit_ld(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, coordinate_id, val_id;
+    SpvImageOperandsMask operands_mask = 0;
+    unsigned int image_operand_count = 0;
+    struct vkd3d_shader_image image;
+    uint32_t image_operands[2];
+    DWORD coordinate_mask;
+    bool multisample;
+
+    multisample = instruction->handler_idx == VKD3DSIH_LD2DMS;
+
+    vkd3d_dxbc_compiler_prepare_image(compiler, &image, &src[1].reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+
+    type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, VKD3D_VEC4_SIZE);
+    coordinate_mask = (1u << image.resource_type_info->coordinate_component_count) - 1;
+    coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], coordinate_mask);
+    if (image.resource_type_info->resource_type != VKD3D_SHADER_RESOURCE_BUFFER && !multisample)
+    {
+        operands_mask |= SpvImageOperandsLodMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                &src[0], VKD3DSP_WRITEMASK_3);
+    }
+    if (vkd3d_shader_instruction_has_texel_offset(instruction))
+    {
+        operands_mask |= SpvImageOperandsConstOffsetMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_texel_offset(compiler,
+                instruction, image.resource_type_info);
+    }
+    if (multisample)
+    {
+        operands_mask |= SpvImageOperandsSampleMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                &src[2], VKD3DSP_WRITEMASK_0);
+    }
+    assert(image_operand_count <= ARRAY_SIZE(image_operands));
+    val_id = vkd3d_spirv_build_op_image_fetch(builder, type_id,
+            image.image_id, coordinate_id, operands_mask, image_operands, image_operand_count);
+
+    vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler,
+            dst, val_id, image.sampled_type, src[1].swizzle);
+}
+
+static void vkd3d_dxbc_compiler_emit_lod(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_shader_src_param *resource, *sampler;
+    uint32_t type_id, coordinate_id, val_id;
+    struct vkd3d_shader_image image;
+
+    vkd3d_spirv_enable_capability(builder, SpvCapabilityImageQuery);
+
+    resource = &src[1];
+    sampler = &src[2];
+    vkd3d_dxbc_compiler_prepare_image(compiler, &image,
+            &resource->reg, &sampler->reg, VKD3D_IMAGE_FLAG_SAMPLED);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
+    coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_ALL);
+    val_id = vkd3d_spirv_build_op_image_query_lod(builder,
+            type_id, image.sampled_image_id, coordinate_id);
+
+    vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler,
+            dst, val_id, image.sampled_type, resource->swizzle);
+}
+
+static void vkd3d_dxbc_compiler_emit_sample(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_shader_src_param *resource, *sampler;
+    uint32_t sampled_type_id, coordinate_id, val_id;
+    SpvImageOperandsMask operands_mask = 0;
+    unsigned int image_operand_count = 0;
+    struct vkd3d_shader_image image;
+    uint32_t image_operands[3];
+    DWORD coordinate_mask;
+    SpvOp op;
+
+    resource = &src[1];
+    sampler = &src[2];
+    vkd3d_dxbc_compiler_prepare_image(compiler, &image,
+            &resource->reg, &sampler->reg, VKD3D_IMAGE_FLAG_SAMPLED);
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_SAMPLE:
+            op = SpvOpImageSampleImplicitLod;
+            break;
+        case VKD3DSIH_SAMPLE_B:
+            op = SpvOpImageSampleImplicitLod;
+            operands_mask |= SpvImageOperandsBiasMask;
+            image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                    &src[3], VKD3DSP_WRITEMASK_0);
+            break;
+        case VKD3DSIH_SAMPLE_GRAD:
+            op = SpvOpImageSampleExplicitLod;
+            operands_mask |= SpvImageOperandsGradMask;
+            coordinate_mask = (1u << image.resource_type_info->offset_component_count) - 1;
+            image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                    &src[3], coordinate_mask);
+            image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                    &src[4], coordinate_mask);
+            break;
+        case VKD3DSIH_SAMPLE_LOD:
+            op = SpvOpImageSampleExplicitLod;
+            operands_mask |= SpvImageOperandsLodMask;
+            image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                    &src[3], VKD3DSP_WRITEMASK_0);
+            break;
+        default:
+            ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+            return;
+    }
+
+    if (vkd3d_shader_instruction_has_texel_offset(instruction))
+    {
+        operands_mask |= SpvImageOperandsConstOffsetMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_texel_offset(compiler,
+                instruction, image.resource_type_info);
+    }
+
+    sampled_type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, VKD3D_VEC4_SIZE);
+    coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_ALL);
+    assert(image_operand_count <= ARRAY_SIZE(image_operands));
+    val_id = vkd3d_spirv_build_op_image_sample(builder, op, sampled_type_id,
+            image.sampled_image_id, coordinate_id, operands_mask, image_operands, image_operand_count);
+
+    vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler,
+            dst, val_id, image.sampled_type, resource->swizzle);
+}
+
+static void vkd3d_dxbc_compiler_emit_sample_c(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t sampled_type_id, coordinate_id, dref_id, val_id, type_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    SpvImageOperandsMask operands_mask = 0;
+    unsigned int image_operand_count = 0;
+    struct vkd3d_shader_image image;
+    uint32_t image_operands[1];
+    SpvOp op;
+
+    if (vkd3d_shader_instruction_has_texel_offset(instruction))
+        FIXME("Texel offset not supported.\n");
+
+    if (instruction->handler_idx == VKD3DSIH_SAMPLE_C_LZ)
+    {
+        op = SpvOpImageSampleDrefExplicitLod;
+        operands_mask |= SpvImageOperandsLodMask;
+        image_operands[image_operand_count++]
+                = vkd3d_dxbc_compiler_get_constant_float(compiler, 0.0f);
+    }
+    else
+    {
+        op = SpvOpImageSampleDrefImplicitLod;
+    }
+
+    vkd3d_dxbc_compiler_prepare_image(compiler,
+            &image, &src[1].reg, &src[2].reg, VKD3D_IMAGE_FLAG_SAMPLED | VKD3D_IMAGE_FLAG_DEPTH);
+    sampled_type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, 1);
+    coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_ALL);
+    dref_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[3], VKD3DSP_WRITEMASK_0);
+    /* XXX: Nvidia is broken and expects that the D_ref is packed together with coordinates. */
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    coordinate_id = vkd3d_spirv_build_op_composite_insert1(builder,
+            type_id, dref_id, coordinate_id, image.resource_type_info->coordinate_component_count);
+    val_id = vkd3d_spirv_build_op_image_sample_dref(builder, op, sampled_type_id,
+            image.sampled_image_id, coordinate_id, dref_id, operands_mask,
+            image_operands, image_operand_count);
+
+    vkd3d_dxbc_compiler_emit_store_dst_scalar(compiler,
+            dst, val_id, image.sampled_type, src[1].swizzle);
+}
+
+static void vkd3d_dxbc_compiler_emit_gather4(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_src_param *addr, *offset, *resource, *sampler;
+    uint32_t sampled_type_id, coordinate_id, component_id, dref_id, val_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    unsigned int image_flags = VKD3D_IMAGE_FLAG_SAMPLED;
+    SpvImageOperandsMask operands_mask = 0;
+    unsigned int image_operand_count = 0;
+    struct vkd3d_shader_image image;
+    unsigned int component_idx;
+    uint32_t image_operands[1];
+    DWORD coordinate_mask;
+    bool extended_offset;
+
+    if (instruction->handler_idx == VKD3DSIH_GATHER4_C
+            || instruction->handler_idx == VKD3DSIH_GATHER4_PO_C)
+        image_flags |= VKD3D_IMAGE_FLAG_DEPTH;
+
+    extended_offset = instruction->handler_idx == VKD3DSIH_GATHER4_PO
+            || instruction->handler_idx == VKD3DSIH_GATHER4_PO_C;
+
+    addr = &src[0];
+    offset = extended_offset ? &src[1] : NULL;
+    resource = &src[1 + extended_offset];
+    sampler = &src[2 + extended_offset];
+
+    vkd3d_dxbc_compiler_prepare_image(compiler, &image,
+            &resource->reg, &sampler->reg, image_flags);
+
+    if (offset)
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityImageGatherExtended);
+        operands_mask |= SpvImageOperandsOffsetMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                offset, (1u << image.resource_type_info->offset_component_count) - 1);
+    }
+    else if (vkd3d_shader_instruction_has_texel_offset(instruction))
+    {
+        operands_mask |= SpvImageOperandsConstOffsetMask;
+        image_operands[image_operand_count++] = vkd3d_dxbc_compiler_emit_texel_offset(compiler,
+                instruction, image.resource_type_info);
+    }
+
+    sampled_type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, VKD3D_VEC4_SIZE);
+    coordinate_mask = (1u << image.resource_type_info->coordinate_component_count) - 1;
+    coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, addr, coordinate_mask);
+    if (image_flags & VKD3D_IMAGE_FLAG_DEPTH)
+    {
+        dref_id = vkd3d_dxbc_compiler_emit_load_src(compiler,
+                &src[3 + extended_offset], VKD3DSP_WRITEMASK_0);
+        val_id = vkd3d_spirv_build_op_image_dref_gather(builder, sampled_type_id,
+                image.sampled_image_id, coordinate_id, dref_id,
+                operands_mask, image_operands, image_operand_count);
+    }
+    else
+    {
+        component_idx = vkd3d_swizzle_get_component(sampler->swizzle, 0);
+        /* Nvidia driver requires signed integer type. */
+        component_id = vkd3d_dxbc_compiler_get_constant(compiler,
+                VKD3D_SHADER_COMPONENT_INT, 1, &component_idx);
+        val_id = vkd3d_spirv_build_op_image_gather(builder, sampled_type_id,
+                image.sampled_image_id, coordinate_id, component_id,
+                operands_mask, image_operands, image_operand_count);
+    }
+
+    vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler,
+            dst, val_id, image.sampled_type, resource->swizzle);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_raw_structured_addressing(
+        struct vkd3d_dxbc_compiler *compiler, uint32_t type_id, unsigned int stride,
+        const struct vkd3d_shader_src_param *src0, DWORD src0_mask,
+        const struct vkd3d_shader_src_param *src1, DWORD src1_mask)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_src_param *offset;
+    uint32_t structure_id = 0, offset_id;
+    DWORD offset_write_mask;
+
+    if (stride)
+    {
+        structure_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src0, src0_mask);
+        structure_id = vkd3d_spirv_build_op_imul(builder, type_id,
+                structure_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, stride));
+    }
+    offset = stride ? src1 : src0;
+    offset_write_mask = stride ? src1_mask : src0_mask;
+
+    offset_id = vkd3d_dxbc_compiler_emit_load_src(compiler, offset, offset_write_mask);
+    offset_id = vkd3d_spirv_build_op_shift_right_logical(builder, type_id,
+            offset_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, 2));
+
+    if (structure_id)
+        return vkd3d_spirv_build_op_iadd(builder, type_id, structure_id, offset_id);
+    else
+        return offset_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_ld_raw_structured_srv_uav(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t coordinate_id, type_id, val_id, texel_type_id, ptr_type_id, ptr_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_shader_src_param *resource;
+    const struct vkd3d_symbol *resource_symbol;
+    uint32_t base_coordinate_id, component_idx;
+    uint32_t constituents[VKD3D_VEC4_SIZE];
+    struct vkd3d_shader_image image;
+    uint32_t indices[2];
+    unsigned int i, j;
+    SpvOp op;
+
+    resource = &src[instruction->src_count - 1];
+    resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &resource->reg);
+
+    if (resource->reg.type == VKD3DSPR_UAV
+            && vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+    {
+        texel_type_id = vkd3d_spirv_get_type_id(builder, resource_symbol->info.resource.sampled_type, 1);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, texel_type_id);
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+                type_id, resource_symbol->info.resource.structure_stride,
+                &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+        assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+        for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+        {
+            if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+                continue;
+
+            component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+            coordinate_id = base_coordinate_id;
+            if (component_idx)
+                coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                        coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+            indices[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+            indices[1] = coordinate_id;
+
+            ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2);
+            constituents[j++] = vkd3d_spirv_build_op_load(builder, texel_type_id, ptr_id, SpvMemoryAccessMaskNone);
+        }
+    }
+    else
+    {
+        if (resource->reg.type == VKD3DSPR_RESOURCE)
+            op = SpvOpImageFetch;
+        else
+            op = SpvOpImageRead;
+
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &resource->reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+                type_id, image.structure_stride, &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+        texel_type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, VKD3D_VEC4_SIZE);
+        assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+        for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+        {
+            if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+                continue;
+
+            component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+            coordinate_id = base_coordinate_id;
+            if (component_idx)
+                coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                        coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+
+            val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+                    op, texel_type_id, image.image_id, coordinate_id);
+            constituents[j++] = vkd3d_spirv_build_op_composite_extract1(builder,
+                    type_id, val_id, 0);
+        }
+    }
+    assert(dst->reg.data_type == VKD3D_DATA_UINT);
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler, dst, VKD3D_SHADER_COMPONENT_UINT, constituents);
+}
+
+static void vkd3d_dxbc_compiler_emit_ld_tgsm(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t coordinate_id, type_id, ptr_type_id, ptr_id;
+    const struct vkd3d_shader_src_param *resource;
+    struct vkd3d_shader_register_info reg_info;
+    uint32_t base_coordinate_id, component_idx;
+    uint32_t constituents[VKD3D_VEC4_SIZE];
+    unsigned int i, j;
+
+    resource = &src[instruction->src_count - 1];
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, &resource->reg, &reg_info))
+        return;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info.storage_class, type_id);
+    base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+            type_id, reg_info.structure_stride, &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+    assert(dst->write_mask & VKD3DSP_WRITEMASK_ALL);
+    for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+        coordinate_id = base_coordinate_id;
+        if (component_idx)
+            coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                    coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+
+        ptr_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, reg_info.id, coordinate_id);
+        constituents[j++] = vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone);
+    }
+    assert(dst->reg.data_type == VKD3D_DATA_UINT);
+    vkd3d_dxbc_compiler_emit_store_dst_components(compiler, dst, VKD3D_SHADER_COMPONENT_UINT, constituents);
+}
+
+static void vkd3d_dxbc_compiler_emit_ld_raw_structured(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_shader_register_type reg_type = instruction->src[instruction->src_count - 1].reg.type;
+    switch (reg_type)
+    {
+        case VKD3DSPR_RESOURCE:
+        case VKD3DSPR_UAV:
+            vkd3d_dxbc_compiler_emit_ld_raw_structured_srv_uav(compiler, instruction);
+            break;
+        case VKD3DSPR_GROUPSHAREDMEM:
+            vkd3d_dxbc_compiler_emit_ld_tgsm(compiler, instruction);
+            break;
+        default:
+            ERR("Unexpected register type %#x.\n", reg_type);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_store_uav_raw_structured(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t coordinate_id, type_id, val_id, data_id, ptr_type_id, ptr_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_symbol *resource_symbol;
+    uint32_t base_coordinate_id, component_idx;
+    const struct vkd3d_shader_src_param *data;
+    struct vkd3d_shader_image image;
+    unsigned int component_count;
+    uint32_t indices[2];
+
+    resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &dst->reg);
+
+    if (vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, resource_symbol->info.resource.sampled_type, 1);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id);
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+                type_id, resource_symbol->info.resource.structure_stride,
+                &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+        data = &src[instruction->src_count - 1];
+        assert(data->reg.data_type == VKD3D_DATA_UINT);
+        val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, data, dst->write_mask);
+
+        component_count = vkd3d_write_mask_component_count(dst->write_mask);
+        for (component_idx = 0; component_idx < component_count; ++component_idx)
+        {
+            data_id = component_count > 1 ?
+                    vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx) : val_id;
+
+            coordinate_id = base_coordinate_id;
+            if (component_idx)
+                coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                        coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+            indices[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+            indices[1] = coordinate_id;
+
+            ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2);
+            vkd3d_spirv_build_op_store(builder, ptr_id, data_id, SpvMemoryAccessMaskNone);
+        }
+    }
+    else
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &dst->reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+        assert((instruction->handler_idx == VKD3DSIH_STORE_STRUCTURED) != !image.structure_stride);
+        base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+                type_id, image.structure_stride, &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+        data = &src[instruction->src_count - 1];
+        assert(data->reg.data_type == VKD3D_DATA_UINT);
+        val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, data, dst->write_mask);
+
+        component_count = vkd3d_write_mask_component_count(dst->write_mask);
+        for (component_idx = 0; component_idx < component_count; ++component_idx)
+        {
+            /* Mesa Vulkan drivers require the texel parameter to be a vector. */
+            data_id = vkd3d_dxbc_compiler_emit_construct_vector(compiler, VKD3D_SHADER_COMPONENT_UINT,
+                    VKD3D_VEC4_SIZE, val_id, component_idx, component_count);
+
+            coordinate_id = base_coordinate_id;
+            if (component_idx)
+                coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                        coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+
+            vkd3d_spirv_build_op_image_write(builder, image.image_id, coordinate_id,
+                    data_id, SpvImageOperandsMaskNone, NULL, 0);
+        }
+    }
+
+}
+
+static void vkd3d_dxbc_compiler_emit_store_tgsm(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t coordinate_id, type_id, val_id, ptr_type_id, ptr_id, data_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t base_coordinate_id, component_idx;
+    const struct vkd3d_shader_src_param *data;
+    struct vkd3d_shader_register_info reg_info;
+    unsigned int component_count;
+
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, &dst->reg, &reg_info))
+        return;
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info.storage_class, type_id);
+    assert((instruction->handler_idx == VKD3DSIH_STORE_STRUCTURED) != !reg_info.structure_stride);
+    base_coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+            type_id, reg_info.structure_stride, &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
+
+    data = &src[instruction->src_count - 1];
+    assert(data->reg.data_type == VKD3D_DATA_UINT);
+    val_id = vkd3d_dxbc_compiler_emit_load_src(compiler, data, dst->write_mask);
+
+    component_count = vkd3d_write_mask_component_count(dst->write_mask);
+    for (component_idx = 0; component_idx < component_count; ++component_idx)
+    {
+        data_id = component_count > 1 ?
+                vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx) : val_id;
+
+        coordinate_id = base_coordinate_id;
+        if (component_idx)
+            coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
+                    coordinate_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx));
+
+        ptr_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, reg_info.id, coordinate_id);
+        vkd3d_spirv_build_op_store(builder, ptr_id, data_id, SpvMemoryAccessMaskNone);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_store_raw_structured(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_shader_register_type reg_type = instruction->dst[0].reg.type;
+    switch (reg_type)
+    {
+        case VKD3DSPR_UAV:
+            vkd3d_dxbc_compiler_emit_store_uav_raw_structured(compiler, instruction);
+            break;
+        case VKD3DSPR_GROUPSHAREDMEM:
+            vkd3d_dxbc_compiler_emit_store_tgsm(compiler, instruction);
+            break;
+        default:
+            ERR("Unexpected register type %#x.\n", reg_type);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_ld_uav_typed(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t coordinate_id, type_id, val_id, ptr_type_id, ptr_id;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_symbol *resource_symbol;
+    struct vkd3d_shader_image image;
+    DWORD coordinate_mask;
+    uint32_t indices[2];
+
+    resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &src[1].reg);
+
+    if (vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, resource_symbol->info.resource.sampled_type, 1);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id);
+        coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
+        indices[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+        indices[1] = coordinate_id;
+
+        ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2);
+        val_id = vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone);
+
+        vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler, dst, val_id,
+                resource_symbol->info.resource.sampled_type, src[1].swizzle);
+    }
+    else
+    {
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &src[1].reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+        type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, VKD3D_VEC4_SIZE);
+        coordinate_mask = (1u << image.resource_type_info->coordinate_component_count) - 1;
+        coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], coordinate_mask);
+
+        val_id = vkd3d_spirv_build_op_image_read(builder, type_id,
+                image.image_id, coordinate_id, SpvImageOperandsMaskNone, NULL, 0);
+
+        vkd3d_dxbc_compiler_emit_store_dst_swizzled(compiler,
+                dst, val_id, image.sampled_type, src[1].swizzle);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_store_uav_typed(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    uint32_t coordinate_id, texel_id, type_id, val_id, ptr_type_id, ptr_id;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_symbol *resource_symbol;
+    struct vkd3d_shader_image image;
+    DWORD coordinate_mask;
+    uint32_t indices[2];
+
+    resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &dst->reg);
+
+    if (vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+    {
+        type_id = vkd3d_spirv_get_type_id(builder, resource_symbol->info.resource.sampled_type, 1);
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id);
+        coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
+        indices[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+        indices[1] = coordinate_id;
+
+        val_id = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler, &src[1],
+                VKD3DSP_WRITEMASK_0, resource_symbol->info.resource.sampled_type);
+        ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2);
+        vkd3d_spirv_build_op_store(builder, ptr_id, val_id, SpvMemoryAccessMaskNone);
+    }
+    else
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityStorageImageWriteWithoutFormat);
+
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &dst->reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+        coordinate_mask = (1u << image.resource_type_info->coordinate_component_count) - 1;
+        coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], coordinate_mask);
+        texel_id = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler, &src[1], dst->write_mask, image.sampled_type);
+
+        vkd3d_spirv_build_op_image_write(builder, image.image_id, coordinate_id, texel_id,
+                SpvImageOperandsMaskNone, NULL, 0);
+    }
+}
+
+static void vkd3d_dxbc_compiler_emit_uav_counter_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    unsigned int memory_semantics = SpvMemorySemanticsMaskNone;
+    uint32_t ptr_type_id, type_id, counter_id, result_id;
+    uint32_t coordinate_id, sample_id, pointer_id;
+    const struct vkd3d_symbol *resource_symbol;
+    uint32_t operands[3];
+    SpvOp op;
+
+    op = instruction->handler_idx == VKD3DSIH_IMM_ATOMIC_ALLOC
+            ? SpvOpAtomicIIncrement : SpvOpAtomicIDecrement;
+
+    resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &src->reg);
+    counter_id = resource_symbol->info.resource.uav_counter_id;
+    assert(counter_id);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    if (vkd3d_dxbc_compiler_is_opengl_target(compiler))
+    {
+        pointer_id = counter_id;
+        memory_semantics |= SpvMemorySemanticsAtomicCounterMemoryMask;
+    }
+    else if (compiler->ssbo_uavs)
+    {
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id);
+        coordinate_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+        operands[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+        operands[1] = coordinate_id;
+        pointer_id = vkd3d_spirv_build_op_access_chain(builder,
+                ptr_type_id, counter_id, operands, 2);
+    }
+    else
+    {
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassImage, type_id);
+        coordinate_id = sample_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+        pointer_id = vkd3d_spirv_build_op_image_texel_pointer(builder,
+                ptr_type_id, counter_id, coordinate_id, sample_id);
+    }
+
+    operands[0] = pointer_id;
+    operands[1] = vkd3d_dxbc_compiler_get_constant_uint(compiler, SpvScopeDevice);
+    operands[2] = vkd3d_dxbc_compiler_get_constant_uint(compiler, memory_semantics);
+    result_id = vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
+            op, type_id, operands, ARRAY_SIZE(operands));
+    if (op == SpvOpAtomicIDecrement)
+    {
+        /* SpvOpAtomicIDecrement returns the original value. */
+        result_id = vkd3d_spirv_build_op_isub(builder, type_id, result_id,
+                vkd3d_dxbc_compiler_get_constant_uint(compiler, 1));
+    }
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, result_id);
+}
+
+static SpvOp vkd3d_dxbc_compiler_map_atomic_instruction(const struct vkd3d_shader_instruction *instruction)
+{
+    static const struct
+    {
+        enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+        SpvOp spirv_op;
+    }
+    atomic_ops[] =
+    {
+        {VKD3DSIH_ATOMIC_AND,          SpvOpAtomicAnd},
+        {VKD3DSIH_ATOMIC_CMP_STORE,    SpvOpAtomicCompareExchange},
+        {VKD3DSIH_ATOMIC_IADD,         SpvOpAtomicIAdd},
+        {VKD3DSIH_ATOMIC_IMAX,         SpvOpAtomicSMax},
+        {VKD3DSIH_ATOMIC_IMIN,         SpvOpAtomicSMin},
+        {VKD3DSIH_ATOMIC_OR,           SpvOpAtomicOr},
+        {VKD3DSIH_ATOMIC_UMAX,         SpvOpAtomicUMax},
+        {VKD3DSIH_ATOMIC_UMIN,         SpvOpAtomicUMin},
+        {VKD3DSIH_ATOMIC_XOR,          SpvOpAtomicXor},
+        {VKD3DSIH_IMM_ATOMIC_AND,      SpvOpAtomicAnd},
+        {VKD3DSIH_IMM_ATOMIC_CMP_EXCH, SpvOpAtomicCompareExchange},
+        {VKD3DSIH_IMM_ATOMIC_EXCH,     SpvOpAtomicExchange},
+        {VKD3DSIH_IMM_ATOMIC_IADD,     SpvOpAtomicIAdd},
+        {VKD3DSIH_IMM_ATOMIC_IMAX,     SpvOpAtomicSMax},
+        {VKD3DSIH_IMM_ATOMIC_IMIN,     SpvOpAtomicSMin},
+        {VKD3DSIH_IMM_ATOMIC_OR,       SpvOpAtomicOr},
+        {VKD3DSIH_IMM_ATOMIC_UMAX,     SpvOpAtomicUMax},
+        {VKD3DSIH_IMM_ATOMIC_UMIN,     SpvOpAtomicUMin},
+        {VKD3DSIH_IMM_ATOMIC_XOR,      SpvOpAtomicXor},
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(atomic_ops); ++i)
+    {
+        if (atomic_ops[i].handler_idx == instruction->handler_idx)
+            return atomic_ops[i].spirv_op;
+    }
+
+    return SpvOpMax;
+}
+
+static bool is_imm_atomic_instruction(enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx)
+{
+    return VKD3DSIH_IMM_ATOMIC_ALLOC <= handler_idx && handler_idx <= VKD3DSIH_IMM_ATOMIC_XOR;
+}
+
+static void vkd3d_dxbc_compiler_emit_atomic_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_symbol *resource_symbol = NULL;
+    uint32_t ptr_type_id, type_id, val_id, result_id;
+    enum vkd3d_shader_component_type component_type;
+    const struct vkd3d_shader_dst_param *resource;
+    uint32_t coordinate_id, sample_id, pointer_id;
+    struct vkd3d_shader_register_info reg_info;
+    struct vkd3d_shader_image image;
+    unsigned int structure_stride;
+    DWORD coordinate_mask;
+    uint32_t operands[6];
+    unsigned int i = 0;
+    SpvScope scope;
+    bool raw;
+    SpvOp op;
+
+    resource = is_imm_atomic_instruction(instruction->handler_idx) ? &dst[1] : &dst[0];
+
+    op = vkd3d_dxbc_compiler_map_atomic_instruction(instruction);
+    if (op == SpvOpMax)
+    {
+        ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
+        return;
+    }
+
+    if (resource->reg.type == VKD3DSPR_GROUPSHAREDMEM)
+    {
+        scope = SpvScopeWorkgroup;
+        coordinate_mask = 1u;
+        if (!vkd3d_dxbc_compiler_get_register_info(compiler, &resource->reg, &reg_info))
+            return;
+        structure_stride = reg_info.structure_stride;
+        raw = !structure_stride;
+    }
+    else
+    {
+        scope = SpvScopeDevice;
+        resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &resource->reg);
+
+        if (vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+        {
+            coordinate_mask = VKD3DSP_WRITEMASK_0;
+            structure_stride = resource_symbol->info.resource.structure_stride;
+            raw = resource_symbol->info.resource.raw;
+        }
+        else
+        {
+            vkd3d_dxbc_compiler_prepare_image(compiler, &image, &resource->reg, NULL, VKD3D_IMAGE_FLAG_NO_LOAD);
+            coordinate_mask = (1u << image.resource_type_info->coordinate_component_count) - 1;
+            structure_stride = image.structure_stride;
+            raw = image.raw;
+        }
+    }
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    if (structure_stride || raw)
+    {
+        assert(!raw != !structure_stride);
+        coordinate_id = vkd3d_dxbc_compiler_emit_raw_structured_addressing(compiler,
+                type_id, structure_stride, &src[0], VKD3DSP_WRITEMASK_0,
+                &src[0], VKD3DSP_WRITEMASK_1);
+    }
+    else
+    {
+        assert(resource->reg.type != VKD3DSPR_GROUPSHAREDMEM);
+        coordinate_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], coordinate_mask);
+    }
+
+    if (resource->reg.type == VKD3DSPR_GROUPSHAREDMEM)
+    {
+        component_type = VKD3D_SHADER_COMPONENT_UINT;
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info.storage_class, type_id);
+        pointer_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, reg_info.id, coordinate_id);
+    }
+    else
+    {
+        if (vkd3d_dxbc_compiler_use_storage_buffer(compiler, &resource_symbol->info.resource))
+        {
+            component_type = resource_symbol->info.resource.sampled_type;
+            type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+            ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id);
+            operands[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+            operands[1] = coordinate_id;
+            pointer_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, operands, 2);
+        }
+        else
+        {
+            component_type = image.sampled_type;
+            type_id = vkd3d_spirv_get_type_id(builder, image.sampled_type, 1);
+            ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassImage, type_id);
+            sample_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+            pointer_id = vkd3d_spirv_build_op_image_texel_pointer(builder,
+                    ptr_type_id, image.id, coordinate_id, sample_id);
+        }
+    }
+
+    val_id = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler, &src[1], VKD3DSP_WRITEMASK_0, component_type);
+
+    operands[i++] = pointer_id;
+    operands[i++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, scope);
+    operands[i++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, SpvMemorySemanticsMaskNone);
+    if (instruction->src_count >= 3)
+    {
+        operands[i++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, SpvMemorySemanticsMaskNone);
+        operands[i++] = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler, &src[2], VKD3DSP_WRITEMASK_0, component_type);
+    }
+    operands[i++] = val_id;
+    result_id = vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
+            op, type_id, operands, i);
+
+    if (is_imm_atomic_instruction(instruction->handler_idx))
+        vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, result_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_bufinfo(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_symbol *resource_symbol;
+    uint32_t type_id, val_id, stride_id;
+    struct vkd3d_shader_image image;
+    uint32_t constituents[2];
+    unsigned int write_mask;
+
+    if (compiler->ssbo_uavs && src->reg.type == VKD3DSPR_UAV)
+    {
+        resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, &src->reg);
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        val_id = vkd3d_spirv_build_op_array_length(builder, type_id, resource_symbol->id, 0);
+        write_mask = VKD3DSP_WRITEMASK_0;
+    }
+    else
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityImageQuery);
+
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &src->reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        val_id = vkd3d_spirv_build_op_image_query_size(builder, type_id, image.image_id);
+        write_mask = VKD3DSP_WRITEMASK_0;
+    }
+
+    if (image.structure_stride)
+    {
+        stride_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, image.structure_stride);
+        constituents[0] = vkd3d_spirv_build_op_udiv(builder, type_id, val_id, stride_id);
+        constituents[1] = stride_id;
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, ARRAY_SIZE(constituents));
+        val_id = vkd3d_spirv_build_op_composite_construct(builder,
+                type_id, constituents, ARRAY_SIZE(constituents));
+        write_mask |= VKD3DSP_WRITEMASK_1;
+    }
+    else if (image.raw)
+    {
+        val_id = vkd3d_spirv_build_op_shift_left_logical(builder, type_id,
+                val_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, 2));
+    }
+
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, write_mask,
+            VKD3D_SHADER_COMPONENT_UINT, src->swizzle, dst->write_mask);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static void vkd3d_dxbc_compiler_emit_resinfo(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t type_id, lod_id, val_id, miplevel_count_id;
+    uint32_t constituents[VKD3D_VEC4_SIZE];
+    unsigned int i, size_component_count;
+    struct vkd3d_shader_image image;
+    bool supports_mipmaps;
+
+    vkd3d_spirv_enable_capability(builder, SpvCapabilityImageQuery);
+
+    vkd3d_dxbc_compiler_prepare_image(compiler, &image, &src[1].reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+    size_component_count = image.resource_type_info->coordinate_component_count;
+    if (image.resource_type_info->dim == SpvDimCube)
+        --size_component_count;
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, size_component_count);
+
+    supports_mipmaps = src[1].reg.type != VKD3DSPR_UAV && !image.resource_type_info->ms;
+    if (supports_mipmaps)
+    {
+        lod_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
+        val_id = vkd3d_spirv_build_op_image_query_size_lod(builder, type_id, image.image_id, lod_id);
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        miplevel_count_id = vkd3d_spirv_build_op_image_query_levels(builder, type_id, image.image_id);
+    }
+    else
+    {
+        val_id = vkd3d_spirv_build_op_image_query_size(builder, type_id, image.image_id);
+        /* For UAVs the returned miplevel count is always 1. */
+        miplevel_count_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 1);
+    }
+
+    constituents[0] = val_id;
+    for (i = 0; i < 3 - size_component_count; ++i)
+        constituents[i + 1] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+    constituents[i + 1] = miplevel_count_id;
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, VKD3D_VEC4_SIZE);
+    val_id = vkd3d_spirv_build_op_composite_construct(builder,
+            type_id, constituents, i + 2);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    if (instruction->flags == VKD3DSI_RESINFO_UINT)
+    {
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+    else
+    {
+        if (instruction->flags)
+            FIXME("Unhandled flags %#x.\n", instruction->flags);
+        val_id = vkd3d_spirv_build_op_convert_utof(builder, type_id, val_id);
+    }
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, VKD3DSP_WRITEMASK_ALL,
+            VKD3D_SHADER_COMPONENT_FLOAT, src[1].swizzle, dst->write_mask);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+static uint32_t vkd3d_dxbc_compiler_emit_query_sample_count(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_src_param *src)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_image image;
+    uint32_t type_id, val_id;
+
+    if (src->reg.type == VKD3DSPR_RASTERIZER)
+    {
+        val_id = vkd3d_dxbc_compiler_emit_uint_shader_parameter(compiler,
+                VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT);
+    }
+    else
+    {
+        vkd3d_spirv_enable_capability(builder, SpvCapabilityImageQuery);
+
+        vkd3d_dxbc_compiler_prepare_image(compiler, &image, &src->reg, NULL, VKD3D_IMAGE_FLAG_NONE);
+        type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+        val_id = vkd3d_spirv_build_op_image_query_samples(builder, type_id, image.image_id);
+    }
+
+    return val_id;
+}
+
+static void vkd3d_dxbc_compiler_emit_sample_info(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    uint32_t constituents[VKD3D_VEC4_SIZE];
+    uint32_t type_id, val_id;
+    unsigned int i;
+
+    val_id = vkd3d_dxbc_compiler_emit_query_sample_count(compiler, src);
+
+    constituents[0] = val_id;
+    for (i = 1; i < VKD3D_VEC4_SIZE; ++i)
+        constituents[i] = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0);
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, VKD3D_VEC4_SIZE);
+    val_id = vkd3d_spirv_build_op_composite_construct(builder, type_id, constituents, VKD3D_VEC4_SIZE);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
+    if (instruction->flags == VKD3DSI_SAMPLE_INFO_UINT)
+    {
+        val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+    }
+    else
+    {
+        if (instruction->flags)
+            FIXME("Unhandled flags %#x.\n", instruction->flags);
+        val_id = vkd3d_spirv_build_op_convert_utof(builder, type_id, val_id);
+    }
+
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, VKD3DSP_WRITEMASK_ALL,
+            VKD3D_SHADER_COMPONENT_FLOAT, src->swizzle, dst->write_mask);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+/* XXX: This is correct only when standard sample positions are used. */
+static void vkd3d_dxbc_compiler_emit_sample_position(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    /* Standard sample locations from the Vulkan spec. */
+    static const float standard_sample_positions[][2] =
+    {
+        /* 1 sample */
+        { 0.0 / 16.0,  0.0 / 16.0},
+        /* 2 samples */
+        { 4.0 / 16.0,  4.0 / 16.0},
+        {-4.0 / 16.0, -4.0 / 16.0},
+        /* 4 samples */
+        {-2.0 / 16.0, -6.0 / 16.0},
+        { 6.0 / 16.0, -2.0 / 16.0},
+        {-6.0 / 16.0,  2.0 / 16.0},
+        { 2.0 / 16.0,  6.0 / 16.0},
+        /* 8 samples */
+        { 1.0 / 16.0, -3.0 / 16.0},
+        {-1.0 / 16.0,  3.0 / 16.0},
+        { 5.0 / 16.0,  1.0 / 16.0},
+        {-3.0 / 16.0, -5.0 / 16.0},
+        {-5.0 / 16.0,  5.0 / 16.0},
+        {-7.0 / 16.0, -1.0 / 16.0},
+        { 3.0 / 16.0,  7.0 / 16.0},
+        { 7.0 / 16.0, -7.0 / 16.0},
+        /* 16 samples */
+        { 1.0 / 16.0,  1.0 / 16.0},
+        {-1.0 / 16.0, -3.0 / 16.0},
+        {-3.0 / 16.0,  2.0 / 16.0},
+        { 4.0 / 16.0, -1.0 / 16.0},
+        {-5.0 / 16.0, -2.0 / 16.0},
+        { 2.0 / 16.0,  5.0 / 16.0},
+        { 5.0 / 16.0,  3.0 / 16.0},
+        { 3.0 / 16.0, -5.0 / 16.0},
+        {-2.0 / 16.0,  6.0 / 16.0},
+        { 0.0 / 16.0, -7.0 / 16.0},
+        {-4.0 / 16.0, -6.0 / 16.0},
+        {-6.0 / 16.0,  4.0 / 16.0},
+        {-8.0 / 16.0,  0.0 / 16.0},
+        { 7.0 / 16.0, -4.0 / 16.0},
+        { 6.0 / 16.0,  7.0 / 16.0},
+        {-7.0 / 16.0, -8.0 / 16.0},
+    };
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t constituents[ARRAY_SIZE(standard_sample_positions)];
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    uint32_t array_type_id, length_id, index_id, id;
+    uint32_t sample_count_id, sample_index_id;
+    uint32_t type_id, bool_id, ptr_type_id;
+    unsigned int i;
+
+    sample_count_id = vkd3d_dxbc_compiler_emit_query_sample_count(compiler, &instruction->src[0]);
+    sample_index_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &instruction->src[1], VKD3DSP_WRITEMASK_0);
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+    index_id = vkd3d_spirv_build_op_iadd(builder, type_id, sample_count_id, sample_index_id);
+    index_id = vkd3d_spirv_build_op_isub(builder,
+            type_id, index_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, 1));
+
+    /* Validate sample index. */
+    bool_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, 1);
+    id = vkd3d_spirv_build_op_logical_and(builder, bool_id,
+            vkd3d_spirv_build_op_uless_than(builder, bool_id, sample_index_id, sample_count_id),
+            vkd3d_spirv_build_op_uless_than_equal(builder,
+                    bool_id, sample_index_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, 16)));
+    index_id = vkd3d_spirv_build_op_select(builder, type_id,
+            id, index_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, 0));
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
+    if (!(id = compiler->sample_positions_id))
+    {
+        length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, ARRAY_SIZE(standard_sample_positions));
+        array_type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
+
+        for (i = 0; i < ARRAY_SIZE(standard_sample_positions); ++ i)
+        {
+            constituents[i] = vkd3d_dxbc_compiler_get_constant(compiler,
+                    VKD3D_SHADER_COMPONENT_FLOAT, 2, (const uint32_t *)standard_sample_positions[i]);
+        }
+
+        id = vkd3d_spirv_build_op_constant_composite(builder, array_type_id, constituents, ARRAY_SIZE(constituents));
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, array_type_id);
+        id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, ptr_type_id, SpvStorageClassPrivate, id);
+        vkd3d_spirv_build_op_name(builder, id, "sample_pos");
+        compiler->sample_positions_id = id;
+    }
+
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
+    id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, id, index_id);
+    id = vkd3d_spirv_build_op_load(builder, type_id, id, SpvMemoryAccessMaskNone);
+
+    id = vkd3d_dxbc_compiler_emit_swizzle(compiler, id, VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1,
+            VKD3D_SHADER_COMPONENT_FLOAT, instruction->src[0].swizzle, dst->write_mask);
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, id);
+}
+
+static void vkd3d_dxbc_compiler_emit_eval_attrib(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_dst_param *dst = instruction->dst;
+    const struct vkd3d_shader_src_param *src = instruction->src;
+    const struct vkd3d_shader_register *input = &src[0].reg;
+    uint32_t instr_set_id, type_id, val_id, src_ids[2];
+    struct vkd3d_shader_register_info register_info;
+    unsigned int src_count = 0;
+    enum GLSLstd450 op;
+
+    if (!vkd3d_dxbc_compiler_get_register_info(compiler, input, &register_info))
+        return;
+
+    if (register_info.storage_class != SpvStorageClassInput)
+    {
+        FIXME("Not supported for storage class %#x.\n", register_info.storage_class);
+        return;
+    }
+
+    vkd3d_spirv_enable_capability(builder, SpvCapabilityInterpolationFunction);
+
+    src_ids[src_count++] = register_info.id;
+
+    if (instruction->handler_idx == VKD3DSIH_EVAL_CENTROID)
+    {
+        op = GLSLstd450InterpolateAtCentroid;
+    }
+    else
+    {
+        assert(instruction->handler_idx == VKD3DSIH_EVAL_SAMPLE_INDEX);
+        op = GLSLstd450InterpolateAtSample;
+        src_ids[src_count++] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], VKD3DSP_WRITEMASK_0);
+    }
+
+    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT,
+            vkd3d_write_mask_component_count(register_info.write_mask));
+
+    instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+    val_id = vkd3d_spirv_build_op_ext_inst(builder, type_id, instr_set_id, op, src_ids, src_count);
+
+    val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, register_info.write_mask,
+            VKD3D_SHADER_COMPONENT_FLOAT, src[0].swizzle, dst->write_mask);
+
+    vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
+/* From the Vulkan spec:
+ *
+ *   "Scope for execution must be limited to: * Workgroup * Subgroup"
+ *
+ *   "Scope for memory must be limited to: * Device * Workgroup * Invocation"
+ */
+static void vkd3d_dxbc_compiler_emit_sync(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    unsigned int memory_semantics = SpvMemorySemanticsAcquireReleaseMask;
+    unsigned int flags = instruction->flags;
+    SpvScope execution_scope = SpvScopeMax;
+    SpvScope memory_scope = SpvScopeDevice;
+
+    if (flags & VKD3DSSF_GROUP_SHARED_MEMORY)
+    {
+        memory_scope = SpvScopeWorkgroup;
+        memory_semantics |= SpvMemorySemanticsWorkgroupMemoryMask;
+        flags &= ~VKD3DSSF_GROUP_SHARED_MEMORY;
+    }
+
+    if (flags & VKD3DSSF_THREAD_GROUP)
+    {
+        execution_scope = SpvScopeWorkgroup;
+        flags &= ~VKD3DSSF_THREAD_GROUP;
+    }
+
+    if (flags)
+    {
+        FIXME("Unhandled sync flags %#x.\n", flags);
+        memory_scope = SpvScopeDevice;
+        execution_scope = SpvScopeWorkgroup;
+        memory_semantics |= SpvMemorySemanticsUniformMemoryMask
+                | SpvMemorySemanticsSubgroupMemoryMask
+                | SpvMemorySemanticsWorkgroupMemoryMask
+                | SpvMemorySemanticsCrossWorkgroupMemoryMask
+                | SpvMemorySemanticsAtomicCounterMemoryMask
+                | SpvMemorySemanticsImageMemoryMask;
+    }
+
+    vkd3d_dxbc_compiler_emit_barrier(compiler, execution_scope, memory_scope, memory_semantics);
+}
+
+static void vkd3d_dxbc_compiler_emit_emit_stream(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int stream_idx;
+
+    if (instruction->handler_idx == VKD3DSIH_EMIT_STREAM)
+        stream_idx = instruction->src[0].reg.idx[0].offset;
+    else
+        stream_idx = 0;
+
+    if (stream_idx)
+    {
+        FIXME("Multiple streams are not supported yet.\n");
+        return;
+    }
+
+    vkd3d_dxbc_compiler_emit_shader_epilogue_invocation(compiler);
+    vkd3d_spirv_build_op_emit_vertex(builder);
+}
+
+static void vkd3d_dxbc_compiler_emit_cut_stream(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    unsigned int stream_idx;
+
+    if (instruction->handler_idx == VKD3DSIH_CUT_STREAM)
+        stream_idx = instruction->src[0].reg.idx[0].offset;
+    else
+        stream_idx = 0;
+
+    if (stream_idx)
+    {
+        FIXME("Multiple streams are not supported yet.\n");
+        return;
+    }
+
+    vkd3d_spirv_build_op_end_primitive(builder);
+}
+
+/* This function is called after declarations are processed. */
+static void vkd3d_dxbc_compiler_emit_main_prolog(struct vkd3d_dxbc_compiler *compiler)
+{
+    vkd3d_dxbc_compiler_emit_push_constant_buffers(compiler);
+
+    if (compiler->xfb_info && compiler->xfb_info->element_count
+            && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY)
+        vkd3d_dxbc_compiler_emit_point_size(compiler);
+}
+
+static bool is_dcl_instruction(enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx)
+{
+    return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
+            || handler_idx == VKD3DSIH_HS_DECLS;
+}
+
+int vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    int ret = VKD3D_OK;
+
+    if (!is_dcl_instruction(instruction->handler_idx) && !compiler->after_declarations_section)
+    {
+        compiler->after_declarations_section = true;
+        vkd3d_dxbc_compiler_emit_main_prolog(compiler);
+    }
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_DCL_GLOBAL_FLAGS:
+            vkd3d_dxbc_compiler_emit_dcl_global_flags(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_TEMPS:
+            vkd3d_dxbc_compiler_emit_dcl_temps(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INDEXABLE_TEMP:
+            vkd3d_dxbc_compiler_emit_dcl_indexable_temp(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_CONSTANT_BUFFER:
+            vkd3d_dxbc_compiler_emit_dcl_constant_buffer(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER:
+            vkd3d_dxbc_compiler_emit_dcl_immediate_constant_buffer(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_SAMPLER:
+            vkd3d_dxbc_compiler_emit_dcl_sampler(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL:
+        case VKD3DSIH_DCL_UAV_TYPED:
+            vkd3d_dxbc_compiler_emit_dcl_resource(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_RESOURCE_RAW:
+        case VKD3DSIH_DCL_UAV_RAW:
+            vkd3d_dxbc_compiler_emit_dcl_resource_raw(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
+        case VKD3DSIH_DCL_UAV_STRUCTURED:
+            vkd3d_dxbc_compiler_emit_dcl_resource_structured(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_TGSM_RAW:
+            vkd3d_dxbc_compiler_emit_dcl_tgsm_raw(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_TGSM_STRUCTURED:
+            vkd3d_dxbc_compiler_emit_dcl_tgsm_structured(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT:
+            vkd3d_dxbc_compiler_emit_dcl_input(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT_PS:
+            vkd3d_dxbc_compiler_emit_dcl_input_ps(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT_PS_SGV:
+        case VKD3DSIH_DCL_INPUT_PS_SIV:
+            vkd3d_dxbc_compiler_emit_dcl_input_ps_sysval(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT_SGV:
+        case VKD3DSIH_DCL_INPUT_SIV:
+            vkd3d_dxbc_compiler_emit_dcl_input_sysval(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_OUTPUT:
+            vkd3d_dxbc_compiler_emit_dcl_output(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_OUTPUT_SIV:
+            vkd3d_dxbc_compiler_emit_dcl_output_siv(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INDEX_RANGE:
+            vkd3d_dxbc_compiler_emit_dcl_index_range(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_STREAM:
+            vkd3d_dxbc_compiler_emit_dcl_stream(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_VERTICES_OUT:
+            vkd3d_dxbc_compiler_emit_output_vertex_count(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT_PRIMITIVE:
+            vkd3d_dxbc_compiler_emit_dcl_input_primitive(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_OUTPUT_TOPOLOGY:
+            vkd3d_dxbc_compiler_emit_dcl_output_topology(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_GS_INSTANCES:
+            vkd3d_dxbc_compiler_emit_dcl_gs_instances(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT:
+            compiler->input_control_point_count = instruction->declaration.count;
+            break;
+        case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT:
+            compiler->output_control_point_count = instruction->declaration.count;
+            vkd3d_dxbc_compiler_emit_output_vertex_count(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_TESSELLATOR_DOMAIN:
+            vkd3d_dxbc_compiler_emit_dcl_tessellator_domain(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE:
+            vkd3d_dxbc_compiler_emit_tessellator_output_primitive(compiler,
+                    instruction->declaration.tessellator_output_primitive);
+            break;
+        case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING:
+            vkd3d_dxbc_compiler_emit_tessellator_partitioning(compiler,
+                    instruction->declaration.tessellator_partitioning);
+            break;
+        case VKD3DSIH_DCL_THREAD_GROUP:
+            vkd3d_dxbc_compiler_emit_dcl_thread_group(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
+        case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
+            ret = vkd3d_dxbc_compiler_emit_shader_phase_instance_count(compiler, instruction);
+            break;
+        case VKD3DSIH_HS_CONTROL_POINT_PHASE:
+        case VKD3DSIH_HS_FORK_PHASE:
+        case VKD3DSIH_HS_JOIN_PHASE:
+            vkd3d_dxbc_compiler_enter_shader_phase(compiler, instruction);
+            break;
+        case VKD3DSIH_MOV:
+            vkd3d_dxbc_compiler_emit_mov(compiler, instruction);
+            break;
+        case VKD3DSIH_MOVC:
+            vkd3d_dxbc_compiler_emit_movc(compiler, instruction);
+            break;
+        case VKD3DSIH_SWAPC:
+            vkd3d_dxbc_compiler_emit_swapc(compiler, instruction);
+            break;
+        case VKD3DSIH_ADD:
+        case VKD3DSIH_AND:
+        case VKD3DSIH_BFREV:
+        case VKD3DSIH_COUNTBITS:
+        case VKD3DSIH_DIV:
+        case VKD3DSIH_FTOI:
+        case VKD3DSIH_FTOU:
+        case VKD3DSIH_IADD:
+        case VKD3DSIH_INEG:
+        case VKD3DSIH_ISHL:
+        case VKD3DSIH_ISHR:
+        case VKD3DSIH_ITOF:
+        case VKD3DSIH_MUL:
+        case VKD3DSIH_NOT:
+        case VKD3DSIH_OR:
+        case VKD3DSIH_USHR:
+        case VKD3DSIH_UTOF:
+        case VKD3DSIH_XOR:
+            vkd3d_dxbc_compiler_emit_alu_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_EXP:
+        case VKD3DSIH_FIRSTBIT_HI:
+        case VKD3DSIH_FIRSTBIT_LO:
+        case VKD3DSIH_FIRSTBIT_SHI:
+        case VKD3DSIH_FRC:
+        case VKD3DSIH_IMAX:
+        case VKD3DSIH_IMIN:
+        case VKD3DSIH_LOG:
+        case VKD3DSIH_MAD:
+        case VKD3DSIH_MAX:
+        case VKD3DSIH_MIN:
+        case VKD3DSIH_ROUND_NE:
+        case VKD3DSIH_ROUND_NI:
+        case VKD3DSIH_ROUND_PI:
+        case VKD3DSIH_ROUND_Z:
+        case VKD3DSIH_RSQ:
+        case VKD3DSIH_SQRT:
+        case VKD3DSIH_UMAX:
+        case VKD3DSIH_UMIN:
+            vkd3d_dxbc_compiler_emit_ext_glsl_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_DP4:
+        case VKD3DSIH_DP3:
+        case VKD3DSIH_DP2:
+            vkd3d_dxbc_compiler_emit_dot(compiler, instruction);
+            break;
+        case VKD3DSIH_RCP:
+            vkd3d_dxbc_compiler_emit_rcp(compiler, instruction);
+            break;
+        case VKD3DSIH_SINCOS:
+            vkd3d_dxbc_compiler_emit_sincos(compiler, instruction);
+            break;
+        case VKD3DSIH_IMUL:
+            vkd3d_dxbc_compiler_emit_imul(compiler, instruction);
+            break;
+        case VKD3DSIH_IMAD:
+            vkd3d_dxbc_compiler_emit_imad(compiler, instruction);
+            break;
+        case VKD3DSIH_UDIV:
+            vkd3d_dxbc_compiler_emit_udiv(compiler, instruction);
+            break;
+        case VKD3DSIH_EQ:
+        case VKD3DSIH_GE:
+        case VKD3DSIH_IEQ:
+        case VKD3DSIH_IGE:
+        case VKD3DSIH_ILT:
+        case VKD3DSIH_INE:
+        case VKD3DSIH_LT:
+        case VKD3DSIH_NE:
+        case VKD3DSIH_UGE:
+        case VKD3DSIH_ULT:
+            vkd3d_dxbc_compiler_emit_comparison_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_BFI:
+        case VKD3DSIH_IBFE:
+        case VKD3DSIH_UBFE:
+            vkd3d_dxbc_compiler_emit_bitfield_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_F16TOF32:
+            vkd3d_dxbc_compiler_emit_f16tof32(compiler, instruction);
+            break;
+        case VKD3DSIH_F32TOF16:
+            vkd3d_dxbc_compiler_emit_f32tof16(compiler, instruction);
+            break;
+        case VKD3DSIH_BREAK:
+        case VKD3DSIH_BREAKP:
+        case VKD3DSIH_CASE:
+        case VKD3DSIH_CONTINUE:
+        case VKD3DSIH_CONTINUEP:
+        case VKD3DSIH_DEFAULT:
+        case VKD3DSIH_ELSE:
+        case VKD3DSIH_ENDIF:
+        case VKD3DSIH_ENDLOOP:
+        case VKD3DSIH_ENDSWITCH:
+        case VKD3DSIH_IF:
+        case VKD3DSIH_LOOP:
+        case VKD3DSIH_RET:
+        case VKD3DSIH_RETP:
+        case VKD3DSIH_SWITCH:
+        case VKD3DSIH_TEXKILL:
+            ret = vkd3d_dxbc_compiler_emit_control_flow_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_DSX:
+        case VKD3DSIH_DSX_COARSE:
+        case VKD3DSIH_DSX_FINE:
+        case VKD3DSIH_DSY:
+        case VKD3DSIH_DSY_COARSE:
+        case VKD3DSIH_DSY_FINE:
+            vkd3d_dxbc_compiler_emit_deriv_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_LD2DMS:
+        case VKD3DSIH_LD:
+            vkd3d_dxbc_compiler_emit_ld(compiler, instruction);
+            break;
+        case VKD3DSIH_LOD:
+            vkd3d_dxbc_compiler_emit_lod(compiler, instruction);
+            break;
+        case VKD3DSIH_SAMPLE:
+        case VKD3DSIH_SAMPLE_B:
+        case VKD3DSIH_SAMPLE_GRAD:
+        case VKD3DSIH_SAMPLE_LOD:
+            vkd3d_dxbc_compiler_emit_sample(compiler, instruction);
+            break;
+        case VKD3DSIH_SAMPLE_C:
+        case VKD3DSIH_SAMPLE_C_LZ:
+            vkd3d_dxbc_compiler_emit_sample_c(compiler, instruction);
+            break;
+        case VKD3DSIH_GATHER4:
+        case VKD3DSIH_GATHER4_C:
+        case VKD3DSIH_GATHER4_PO:
+        case VKD3DSIH_GATHER4_PO_C:
+            vkd3d_dxbc_compiler_emit_gather4(compiler, instruction);
+            break;
+        case VKD3DSIH_LD_RAW:
+        case VKD3DSIH_LD_STRUCTURED:
+            vkd3d_dxbc_compiler_emit_ld_raw_structured(compiler, instruction);
+            break;
+        case VKD3DSIH_STORE_RAW:
+        case VKD3DSIH_STORE_STRUCTURED:
+            vkd3d_dxbc_compiler_emit_store_raw_structured(compiler, instruction);
+            break;
+        case VKD3DSIH_LD_UAV_TYPED:
+            vkd3d_dxbc_compiler_emit_ld_uav_typed(compiler, instruction);
+            break;
+        case VKD3DSIH_STORE_UAV_TYPED:
+            vkd3d_dxbc_compiler_emit_store_uav_typed(compiler, instruction);
+            break;
+        case VKD3DSIH_IMM_ATOMIC_ALLOC:
+        case VKD3DSIH_IMM_ATOMIC_CONSUME:
+            vkd3d_dxbc_compiler_emit_uav_counter_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_ATOMIC_AND:
+        case VKD3DSIH_ATOMIC_CMP_STORE:
+        case VKD3DSIH_ATOMIC_IADD:
+        case VKD3DSIH_ATOMIC_IMAX:
+        case VKD3DSIH_ATOMIC_IMIN:
+        case VKD3DSIH_ATOMIC_OR:
+        case VKD3DSIH_ATOMIC_UMAX:
+        case VKD3DSIH_ATOMIC_UMIN:
+        case VKD3DSIH_ATOMIC_XOR:
+        case VKD3DSIH_IMM_ATOMIC_AND:
+        case VKD3DSIH_IMM_ATOMIC_CMP_EXCH:
+        case VKD3DSIH_IMM_ATOMIC_EXCH:
+        case VKD3DSIH_IMM_ATOMIC_IADD:
+        case VKD3DSIH_IMM_ATOMIC_IMAX:
+        case VKD3DSIH_IMM_ATOMIC_IMIN:
+        case VKD3DSIH_IMM_ATOMIC_OR:
+        case VKD3DSIH_IMM_ATOMIC_UMAX:
+        case VKD3DSIH_IMM_ATOMIC_UMIN:
+        case VKD3DSIH_IMM_ATOMIC_XOR:
+            vkd3d_dxbc_compiler_emit_atomic_instruction(compiler, instruction);
+            break;
+        case VKD3DSIH_BUFINFO:
+            vkd3d_dxbc_compiler_emit_bufinfo(compiler, instruction);
+            break;
+        case VKD3DSIH_RESINFO:
+            vkd3d_dxbc_compiler_emit_resinfo(compiler, instruction);
+            break;
+        case VKD3DSIH_SAMPLE_INFO:
+            vkd3d_dxbc_compiler_emit_sample_info(compiler, instruction);
+            break;
+        case VKD3DSIH_SAMPLE_POS:
+            vkd3d_dxbc_compiler_emit_sample_position(compiler, instruction);
+            break;
+        case VKD3DSIH_EVAL_CENTROID:
+        case VKD3DSIH_EVAL_SAMPLE_INDEX:
+            vkd3d_dxbc_compiler_emit_eval_attrib(compiler, instruction);
+            break;
+        case VKD3DSIH_SYNC:
+            vkd3d_dxbc_compiler_emit_sync(compiler, instruction);
+            break;
+        case VKD3DSIH_EMIT:
+        case VKD3DSIH_EMIT_STREAM:
+            vkd3d_dxbc_compiler_emit_emit_stream(compiler, instruction);
+            break;
+        case VKD3DSIH_CUT:
+        case VKD3DSIH_CUT_STREAM:
+            vkd3d_dxbc_compiler_emit_cut_stream(compiler, instruction);
+            break;
+        case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
+        case VKD3DSIH_HS_DECLS:
+        case VKD3DSIH_NOP:
+            /* nothing to do */
+            break;
+        default:
+            FIXME("Unhandled instruction %#x.\n", instruction->handler_idx);
+    }
+
+    return ret;
+}
+
+int vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *spirv)
+{
+    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
+    const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info;
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    const struct vkd3d_shader_phase *phase;
+
+    if ((phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler)))
+        vkd3d_dxbc_compiler_leave_shader_phase(compiler, phase);
+    else
+        vkd3d_spirv_build_op_function_end(builder);
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
+        vkd3d_dxbc_compiler_emit_hull_shader_main(compiler);
+
+    if (compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN)
+    {
+        if (info && (ds_info = vkd3d_find_struct(compile_info->next, SPIRV_DOMAIN_SHADER_TARGET_INFO)))
+        {
+            vkd3d_dxbc_compiler_emit_tessellator_output_primitive(compiler, ds_info->output_primitive);
+            vkd3d_dxbc_compiler_emit_tessellator_partitioning(compiler, ds_info->partitioning);
+        }
+        else if (vkd3d_dxbc_compiler_is_opengl_target(compiler))
+        {
+            ERR("vkd3d_shader_spirv_domain_shader_target_info is required for "
+                    "OpenGL tessellation evaluation shader.\n");
+        }
+    }
+
+    if (compiler->epilogue_function_id)
+    {
+        vkd3d_spirv_build_op_name(builder, compiler->epilogue_function_id, "epilogue");
+        vkd3d_dxbc_compiler_emit_shader_epilogue_function(compiler);
+    }
+
+    if (compiler->strip_debug)
+        vkd3d_spirv_stream_clear(&builder->debug_stream);
+
+    if (!vkd3d_spirv_compile_module(builder, spirv, vkd3d_dxbc_compiler_get_entry_point_name(compiler)))
+        return VKD3D_ERROR;
+
+    if (TRACE_ON())
+    {
+        enum vkd3d_shader_spirv_environment environment = vkd3d_dxbc_compiler_get_target_environment(compiler);
+        vkd3d_spirv_dump(spirv, environment);
+        vkd3d_spirv_validate(spirv, environment);
+    }
+
+    if (compiler->failed)
+        return VKD3D_ERROR_INVALID_SHADER;
+
+    if (compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_TEXT)
+    {
+        struct vkd3d_shader_code text;
+        enum vkd3d_shader_spirv_environment environment = vkd3d_dxbc_compiler_get_target_environment(compiler);
+        if (vkd3d_spirv_binary_to_text(spirv, environment,
+                    get_binary_to_text_options(compiler->formatting), &text) != VKD3D_OK)
+            return VKD3D_ERROR;
+        *spirv = text;
+    }
+
+    return VKD3D_OK;
+}
+
+void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler)
+{
+    vkd3d_free(compiler->control_flow_info);
+
+    vkd3d_free(compiler->output_info);
+
+    vkd3d_free(compiler->push_constants);
+
+    vkd3d_spirv_builder_free(&compiler->spirv_builder);
+
+    rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
+
+    vkd3d_free(compiler->shader_phases);
+    vkd3d_free(compiler->spec_constants);
+
+    vkd3d_free(compiler);
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/trace.c b/dlls/vkd3d/libs/vkd3d-shader/trace.c
new file mode 100644
index 00000000000..d7495ee93c8
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/trace.c
@@ -0,0 +1,1602 @@
+/*
+ * Copyright 2002-2003 Jason Edmeades
+ * Copyright 2002-2003 Raphael Junqueira
+ * Copyright 2004 Christian Costa
+ * Copyright 2005 Oliver Stieber
+ * Copyright 2006 Ivan Gyurdiev
+ * Copyright 2007-2008, 2013 Stefan Dösinger for CodeWeavers
+ * Copyright 2009-2011 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_shader_private.h"
+
+#include <stdio.h>
+
+static const char * const shader_opcode_names[] =
+{
+    /* VKD3DSIH_ABS                              */ "abs",
+    /* VKD3DSIH_ADD                              */ "add",
+    /* VKD3DSIH_AND                              */ "and",
+    /* VKD3DSIH_ATOMIC_AND                       */ "atomic_and",
+    /* VKD3DSIH_ATOMIC_CMP_STORE                 */ "atomic_cmp_store",
+    /* VKD3DSIH_ATOMIC_IADD                      */ "atomic_iadd",
+    /* VKD3DSIH_ATOMIC_IMAX                      */ "atomic_imax",
+    /* VKD3DSIH_ATOMIC_IMIN                      */ "atomic_imin",
+    /* VKD3DSIH_ATOMIC_OR                        */ "atomic_or",
+    /* VKD3DSIH_ATOMIC_UMAX                      */ "atomic_umax",
+    /* VKD3DSIH_ATOMIC_UMIN                      */ "atomic_umin",
+    /* VKD3DSIH_ATOMIC_XOR                       */ "atomic_xor",
+    /* VKD3DSIH_BEM                              */ "bem",
+    /* VKD3DSIH_BFI                              */ "bfi",
+    /* VKD3DSIH_BFREV                            */ "bfrev",
+    /* VKD3DSIH_BREAK                            */ "break",
+    /* VKD3DSIH_BREAKC                           */ "breakc",
+    /* VKD3DSIH_BREAKP                           */ "breakp",
+    /* VKD3DSIH_BUFINFO                          */ "bufinfo",
+    /* VKD3DSIH_CALL                             */ "call",
+    /* VKD3DSIH_CALLNZ                           */ "callnz",
+    /* VKD3DSIH_CASE                             */ "case",
+    /* VKD3DSIH_CMP                              */ "cmp",
+    /* VKD3DSIH_CND                              */ "cnd",
+    /* VKD3DSIH_CONTINUE                         */ "continue",
+    /* VKD3DSIH_CONTINUEP                        */ "continuec",
+    /* VKD3DSIH_COUNTBITS                        */ "countbits",
+    /* VKD3DSIH_CRS                              */ "crs",
+    /* VKD3DSIH_CUT                              */ "cut",
+    /* VKD3DSIH_CUT_STREAM                       */ "cut_stream",
+    /* VKD3DSIH_DCL                              */ "dcl",
+    /* VKD3DSIH_DCL_CONSTANT_BUFFER              */ "dcl_constantBuffer",
+    /* VKD3DSIH_DCL_FUNCTION_BODY                */ "dcl_function_body",
+    /* VKD3DSIH_DCL_FUNCTION_TABLE               */ "dcl_function_table",
+    /* VKD3DSIH_DCL_GLOBAL_FLAGS                 */ "dcl_globalFlags",
+    /* VKD3DSIH_DCL_GS_INSTANCES                 */ "dcl_gs_instances",
+    /* VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT */ "dcl_hs_fork_phase_instance_count",
+    /* VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT */ "dcl_hs_join_phase_instance_count",
+    /* VKD3DSIH_DCL_HS_MAX_TESSFACTOR            */ "dcl_hs_max_tessfactor",
+    /* VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER    */ "dcl_immediateConstantBuffer",
+    /* VKD3DSIH_DCL_INDEX_RANGE                  */ "dcl_index_range",
+    /* VKD3DSIH_DCL_INDEXABLE_TEMP               */ "dcl_indexableTemp",
+    /* VKD3DSIH_DCL_INPUT                        */ "dcl_input",
+    /* VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT    */ "dcl_input_control_point_count",
+    /* VKD3DSIH_DCL_INPUT_PRIMITIVE              */ "dcl_inputPrimitive",
+    /* VKD3DSIH_DCL_INPUT_PS                     */ "dcl_input_ps",
+    /* VKD3DSIH_DCL_INPUT_PS_SGV                 */ "dcl_input_ps_sgv",
+    /* VKD3DSIH_DCL_INPUT_PS_SIV                 */ "dcl_input_ps_siv",
+    /* VKD3DSIH_DCL_INPUT_SGV                    */ "dcl_input_sgv",
+    /* VKD3DSIH_DCL_INPUT_SIV                    */ "dcl_input_siv",
+    /* VKD3DSIH_DCL_INTERFACE                    */ "dcl_interface",
+    /* VKD3DSIH_DCL_OUTPUT                       */ "dcl_output",
+    /* VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT   */ "dcl_output_control_point_count",
+    /* VKD3DSIH_DCL_OUTPUT_SIV                   */ "dcl_output_siv",
+    /* VKD3DSIH_DCL_OUTPUT_TOPOLOGY              */ "dcl_outputTopology",
+    /* VKD3DSIH_DCL_RESOURCE_RAW                 */ "dcl_resource_raw",
+    /* VKD3DSIH_DCL_RESOURCE_STRUCTURED          */ "dcl_resource_structured",
+    /* VKD3DSIH_DCL_SAMPLER                      */ "dcl_sampler",
+    /* VKD3DSIH_DCL_STREAM                       */ "dcl_stream",
+    /* VKD3DSIH_DCL_TEMPS                        */ "dcl_temps",
+    /* VKD3DSIH_DCL_TESSELLATOR_DOMAIN           */ "dcl_tessellator_domain",
+    /* VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE */ "dcl_tessellator_output_primitive",
+    /* VKD3DSIH_DCL_TESSELLATOR_PARTITIONING     */ "dcl_tessellator_partitioning",
+    /* VKD3DSIH_DCL_TGSM_RAW                     */ "dcl_tgsm_raw",
+    /* VKD3DSIH_DCL_TGSM_STRUCTURED              */ "dcl_tgsm_structured",
+    /* VKD3DSIH_DCL_THREAD_GROUP                 */ "dcl_thread_group",
+    /* VKD3DSIH_DCL_UAV_RAW                      */ "dcl_uav_raw",
+    /* VKD3DSIH_DCL_UAV_STRUCTURED               */ "dcl_uav_structured",
+    /* VKD3DSIH_DCL_UAV_TYPED                    */ "dcl_uav_typed",
+    /* VKD3DSIH_DCL_VERTICES_OUT                 */ "dcl_maxOutputVertexCount",
+    /* VKD3DSIH_DEF                              */ "def",
+    /* VKD3DSIH_DEFAULT                          */ "default",
+    /* VKD3DSIH_DEFB                             */ "defb",
+    /* VKD3DSIH_DEFI                             */ "defi",
+    /* VKD3DSIH_DIV                              */ "div",
+    /* VKD3DSIH_DP2                              */ "dp2",
+    /* VKD3DSIH_DP2ADD                           */ "dp2add",
+    /* VKD3DSIH_DP3                              */ "dp3",
+    /* VKD3DSIH_DP4                              */ "dp4",
+    /* VKD3DSIH_DST                              */ "dst",
+    /* VKD3DSIH_DSX                              */ "dsx",
+    /* VKD3DSIH_DSX_COARSE                       */ "deriv_rtx_coarse",
+    /* VKD3DSIH_DSX_FINE                         */ "deriv_rtx_fine",
+    /* VKD3DSIH_DSY                              */ "dsy",
+    /* VKD3DSIH_DSY_COARSE                       */ "deriv_rty_coarse",
+    /* VKD3DSIH_DSY_FINE                         */ "deriv_rty_fine",
+    /* VKD3DSIH_ELSE                             */ "else",
+    /* VKD3DSIH_EMIT                             */ "emit",
+    /* VKD3DSIH_EMIT_STREAM                      */ "emit_stream",
+    /* VKD3DSIH_ENDIF                            */ "endif",
+    /* VKD3DSIH_ENDLOOP                          */ "endloop",
+    /* VKD3DSIH_ENDREP                           */ "endrep",
+    /* VKD3DSIH_ENDSWITCH                        */ "endswitch",
+    /* VKD3DSIH_EQ                               */ "eq",
+    /* VKD3DSIH_EVAL_CENTROID                    */ "eval_centroid",
+    /* VKD3DSIH_EVAL_SAMPLE_INDEX                */ "eval_sample_index",
+    /* VKD3DSIH_EXP                              */ "exp",
+    /* VKD3DSIH_EXPP                             */ "expp",
+    /* VKD3DSIH_F16TOF32                         */ "f16tof32",
+    /* VKD3DSIH_F32TOF16                         */ "f32tof16",
+    /* VKD3DSIH_FCALL                            */ "fcall",
+    /* VKD3DSIH_FIRSTBIT_HI                      */ "firstbit_hi",
+    /* VKD3DSIH_FIRSTBIT_LO                      */ "firstbit_lo",
+    /* VKD3DSIH_FIRSTBIT_SHI                     */ "firstbit_shi",
+    /* VKD3DSIH_FRC                              */ "frc",
+    /* VKD3DSIH_FTOI                             */ "ftoi",
+    /* VKD3DSIH_FTOU                             */ "ftou",
+    /* VKD3DSIH_GATHER4                          */ "gather4",
+    /* VKD3DSIH_GATHER4_C                        */ "gather4_c",
+    /* VKD3DSIH_GATHER4_PO                       */ "gather4_po",
+    /* VKD3DSIH_GATHER4_PO_C                     */ "gather4_po_c",
+    /* VKD3DSIH_GE                               */ "ge",
+    /* VKD3DSIH_HS_CONTROL_POINT_PHASE           */ "hs_control_point_phase",
+    /* VKD3DSIH_HS_DECLS                         */ "hs_decls",
+    /* VKD3DSIH_HS_FORK_PHASE                    */ "hs_fork_phase",
+    /* VKD3DSIH_HS_JOIN_PHASE                    */ "hs_join_phase",
+    /* VKD3DSIH_IADD                             */ "iadd",
+    /* VKD3DSIH_IBFE                             */ "ibfe",
+    /* VKD3DSIH_IEQ                              */ "ieq",
+    /* VKD3DSIH_IF                               */ "if",
+    /* VKD3DSIH_IFC                              */ "ifc",
+    /* VKD3DSIH_IGE                              */ "ige",
+    /* VKD3DSIH_ILT                              */ "ilt",
+    /* VKD3DSIH_IMAD                             */ "imad",
+    /* VKD3DSIH_IMAX                             */ "imax",
+    /* VKD3DSIH_IMIN                             */ "imin",
+    /* VKD3DSIH_IMM_ATOMIC_ALLOC                 */ "imm_atomic_alloc",
+    /* VKD3DSIH_IMM_ATOMIC_AND                   */ "imm_atomic_and",
+    /* VKD3DSIH_IMM_ATOMIC_CMP_EXCH              */ "imm_atomic_cmp_exch",
+    /* VKD3DSIH_IMM_ATOMIC_CONSUME               */ "imm_atomic_consume",
+    /* VKD3DSIH_IMM_ATOMIC_EXCH                  */ "imm_atomic_exch",
+    /* VKD3DSIH_IMM_ATOMIC_IADD                  */ "imm_atomic_iadd",
+    /* VKD3DSIH_IMM_ATOMIC_IMAX                  */ "imm_atomic_imax",
+    /* VKD3DSIH_IMM_ATOMIC_IMIN                  */ "imm_atomic_imin",
+    /* VKD3DSIH_IMM_ATOMIC_OR                    */ "imm_atomic_or",
+    /* VKD3DSIH_IMM_ATOMIC_UMAX                  */ "imm_atomic_umax",
+    /* VKD3DSIH_IMM_ATOMIC_UMIN                  */ "imm_atomic_umin",
+    /* VKD3DSIH_IMM_ATOMIC_XOR                   */ "imm_atomic_xor",
+    /* VKD3DSIH_IMUL                             */ "imul",
+    /* VKD3DSIH_INE                              */ "ine",
+    /* VKD3DSIH_INEG                             */ "ineg",
+    /* VKD3DSIH_ISHL                             */ "ishl",
+    /* VKD3DSIH_ISHR                             */ "ishr",
+    /* VKD3DSIH_ITOF                             */ "itof",
+    /* VKD3DSIH_LABEL                            */ "label",
+    /* VKD3DSIH_LD                               */ "ld",
+    /* VKD3DSIH_LD2DMS                           */ "ld2dms",
+    /* VKD3DSIH_LD_RAW                           */ "ld_raw",
+    /* VKD3DSIH_LD_STRUCTURED                    */ "ld_structured",
+    /* VKD3DSIH_LD_UAV_TYPED                     */ "ld_uav_typed",
+    /* VKD3DSIH_LIT                              */ "lit",
+    /* VKD3DSIH_LOD                              */ "lod",
+    /* VKD3DSIH_LOG                              */ "log",
+    /* VKD3DSIH_LOGP                             */ "logp",
+    /* VKD3DSIH_LOOP                             */ "loop",
+    /* VKD3DSIH_LRP                              */ "lrp",
+    /* VKD3DSIH_LT                               */ "lt",
+    /* VKD3DSIH_M3x2                             */ "m3x2",
+    /* VKD3DSIH_M3x3                             */ "m3x3",
+    /* VKD3DSIH_M3x4                             */ "m3x4",
+    /* VKD3DSIH_M4x3                             */ "m4x3",
+    /* VKD3DSIH_M4x4                             */ "m4x4",
+    /* VKD3DSIH_MAD                              */ "mad",
+    /* VKD3DSIH_MAX                              */ "max",
+    /* VKD3DSIH_MIN                              */ "min",
+    /* VKD3DSIH_MOV                              */ "mov",
+    /* VKD3DSIH_MOVA                             */ "mova",
+    /* VKD3DSIH_MOVC                             */ "movc",
+    /* VKD3DSIH_MUL                              */ "mul",
+    /* VKD3DSIH_NE                               */ "ne",
+    /* VKD3DSIH_NOP                              */ "nop",
+    /* VKD3DSIH_NOT                              */ "not",
+    /* VKD3DSIH_NRM                              */ "nrm",
+    /* VKD3DSIH_OR                               */ "or",
+    /* VKD3DSIH_PHASE                            */ "phase",
+    /* VKD3DSIH_POW                              */ "pow",
+    /* VKD3DSIH_RCP                              */ "rcp",
+    /* VKD3DSIH_REP                              */ "rep",
+    /* VKD3DSIH_RESINFO                          */ "resinfo",
+    /* VKD3DSIH_RET                              */ "ret",
+    /* VKD3DSIH_RETP                             */ "retp",
+    /* VKD3DSIH_ROUND_NE                         */ "round_ne",
+    /* VKD3DSIH_ROUND_NI                         */ "round_ni",
+    /* VKD3DSIH_ROUND_PI                         */ "round_pi",
+    /* VKD3DSIH_ROUND_Z                          */ "round_z",
+    /* VKD3DSIH_RSQ                              */ "rsq",
+    /* VKD3DSIH_SAMPLE                           */ "sample",
+    /* VKD3DSIH_SAMPLE_B                         */ "sample_b",
+    /* VKD3DSIH_SAMPLE_C                         */ "sample_c",
+    /* VKD3DSIH_SAMPLE_C_LZ                      */ "sample_c_lz",
+    /* VKD3DSIH_SAMPLE_GRAD                      */ "sample_d",
+    /* VKD3DSIH_SAMPLE_INFO                      */ "sample_info",
+    /* VKD3DSIH_SAMPLE_LOD                       */ "sample_l",
+    /* VKD3DSIH_SAMPLE_POS                       */ "sample_pos",
+    /* VKD3DSIH_SETP                             */ "setp",
+    /* VKD3DSIH_SGE                              */ "sge",
+    /* VKD3DSIH_SGN                              */ "sgn",
+    /* VKD3DSIH_SINCOS                           */ "sincos",
+    /* VKD3DSIH_SLT                              */ "slt",
+    /* VKD3DSIH_SQRT                             */ "sqrt",
+    /* VKD3DSIH_STORE_RAW                        */ "store_raw",
+    /* VKD3DSIH_STORE_STRUCTURED                 */ "store_structured",
+    /* VKD3DSIH_STORE_UAV_TYPED                  */ "store_uav_typed",
+    /* VKD3DSIH_SUB                              */ "sub",
+    /* VKD3DSIH_SWAPC                            */ "swapc",
+    /* VKD3DSIH_SWITCH                           */ "switch",
+    /* VKD3DSIH_SYNC                             */ "sync",
+    /* VKD3DSIH_TEX                              */ "texld",
+    /* VKD3DSIH_TEXBEM                           */ "texbem",
+    /* VKD3DSIH_TEXBEML                          */ "texbeml",
+    /* VKD3DSIH_TEXCOORD                         */ "texcrd",
+    /* VKD3DSIH_TEXDEPTH                         */ "texdepth",
+    /* VKD3DSIH_TEXDP3                           */ "texdp3",
+    /* VKD3DSIH_TEXDP3TEX                        */ "texdp3tex",
+    /* VKD3DSIH_TEXKILL                          */ "texkill",
+    /* VKD3DSIH_TEXLDD                           */ "texldd",
+    /* VKD3DSIH_TEXLDL                           */ "texldl",
+    /* VKD3DSIH_TEXM3x2DEPTH                     */ "texm3x2depth",
+    /* VKD3DSIH_TEXM3x2PAD                       */ "texm3x2pad",
+    /* VKD3DSIH_TEXM3x2TEX                       */ "texm3x2tex",
+    /* VKD3DSIH_TEXM3x3                          */ "texm3x3",
+    /* VKD3DSIH_TEXM3x3DIFF                      */ "texm3x3diff",
+    /* VKD3DSIH_TEXM3x3PAD                       */ "texm3x3pad",
+    /* VKD3DSIH_TEXM3x3SPEC                      */ "texm3x3spec",
+    /* VKD3DSIH_TEXM3x3TEX                       */ "texm3x3tex",
+    /* VKD3DSIH_TEXM3x3VSPEC                     */ "texm3x3vspec",
+    /* VKD3DSIH_TEXREG2AR                        */ "texreg2ar",
+    /* VKD3DSIH_TEXREG2GB                        */ "texreg2gb",
+    /* VKD3DSIH_TEXREG2RGB                       */ "texreg2rgb",
+    /* VKD3DSIH_UBFE                             */ "ubfe",
+    /* VKD3DSIH_UDIV                             */ "udiv",
+    /* VKD3DSIH_UGE                              */ "uge",
+    /* VKD3DSIH_ULT                              */ "ult",
+    /* VKD3DSIH_UMAX                             */ "umax",
+    /* VKD3DSIH_UMIN                             */ "umin",
+    /* VKD3DSIH_UMUL                             */ "umul",
+    /* VKD3DSIH_USHR                             */ "ushr",
+    /* VKD3DSIH_UTOF                             */ "utof",
+    /* VKD3DSIH_XOR                              */ "xor",
+};
+
+static const struct
+{
+    enum vkd3d_shader_input_sysval_semantic sysval_semantic;
+    const char *sysval_name;
+}
+shader_input_sysval_semantic_names[] =
+{
+    {VKD3D_SIV_POSITION,                   "position"},
+    {VKD3D_SIV_CLIP_DISTANCE,              "clip_distance"},
+    {VKD3D_SIV_CULL_DISTANCE,              "cull_distance"},
+    {VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX,  "render_target_array_index"},
+    {VKD3D_SIV_VIEWPORT_ARRAY_INDEX,       "viewport_array_index"},
+    {VKD3D_SIV_VERTEX_ID,                  "vertex_id"},
+    {VKD3D_SIV_INSTANCE_ID,                "instance_id"},
+    {VKD3D_SIV_PRIMITIVE_ID,               "primitive_id"},
+    {VKD3D_SIV_IS_FRONT_FACE,              "is_front_face"},
+    {VKD3D_SIV_SAMPLE_INDEX,               "sample_index"},
+    {VKD3D_SIV_QUAD_U0_TESS_FACTOR,        "finalQuadUeq0EdgeTessFactor"},
+    {VKD3D_SIV_QUAD_V0_TESS_FACTOR,        "finalQuadVeq0EdgeTessFactor"},
+    {VKD3D_SIV_QUAD_U1_TESS_FACTOR,        "finalQuadUeq1EdgeTessFactor"},
+    {VKD3D_SIV_QUAD_V1_TESS_FACTOR,        "finalQuadVeq1EdgeTessFactor"},
+    {VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR,   "finalQuadUInsideTessFactor"},
+    {VKD3D_SIV_QUAD_V_INNER_TESS_FACTOR,   "finalQuadVInsideTessFactor"},
+    {VKD3D_SIV_TRIANGLE_U_TESS_FACTOR,     "finalTriUeq0EdgeTessFactor"},
+    {VKD3D_SIV_TRIANGLE_V_TESS_FACTOR,     "finalTriVeq0EdgeTessFactor"},
+    {VKD3D_SIV_TRIANGLE_W_TESS_FACTOR,     "finalTriWeq0EdgeTessFactor"},
+    {VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR, "finalTriInsideTessFactor"},
+    {VKD3D_SIV_LINE_DETAIL_TESS_FACTOR,    "finalLineDetailTessFactor"},
+    {VKD3D_SIV_LINE_DENSITY_TESS_FACTOR,   "finalLineDensityTessFactor"},
+};
+
+static int shader_ver_ge(const struct vkd3d_shader_version *v, int major, int minor)
+{
+    return v->major > major || (v->major == major && v->minor >= minor);
+}
+
+static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...)
+{
+    va_list args;
+    int ret;
+
+    va_start(args, format);
+    ret = vkd3d_string_buffer_vprintf(buffer, format, args);
+    va_end(args);
+
+    return ret;
+}
+
+/* Convert floating point offset relative to a register file to an absolute
+ * offset for float constants. */
+static unsigned int shader_get_float_offset(enum vkd3d_shader_register_type register_type, UINT register_idx)
+{
+    switch (register_type)
+    {
+        case VKD3DSPR_CONST: return register_idx;
+        case VKD3DSPR_CONST2: return 2048 + register_idx;
+        case VKD3DSPR_CONST3: return 4096 + register_idx;
+        case VKD3DSPR_CONST4: return 6144 + register_idx;
+        default:
+            FIXME("Unsupported register type: %u.\n", register_type);
+            return register_idx;
+    }
+}
+
+static void shader_dump_global_flags(struct vkd3d_string_buffer *buffer, DWORD global_flags)
+{
+    unsigned int i;
+
+    static const struct
+    {
+        unsigned int flag;
+        const char *name;
+    }
+    global_flag_info[] =
+    {
+        {VKD3DSGF_REFACTORING_ALLOWED,               "refactoringAllowed"},
+        {VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL,         "forceEarlyDepthStencil"},
+        {VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS, "enableRawAndStructuredBuffers"},
+        {VKD3DSGF_ENABLE_MINIMUM_PRECISION,          "enableMinimumPrecision"},
+        {VKD3DSGF_SKIP_OPTIMIZATION,                 "skipOptimization"},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(global_flag_info); ++i)
+    {
+        if (global_flags & global_flag_info[i].flag)
+        {
+            shader_addline(buffer, "%s", global_flag_info[i].name);
+            global_flags &= ~global_flag_info[i].flag;
+            if (global_flags)
+                shader_addline(buffer, " | ");
+        }
+    }
+
+    if (global_flags)
+        shader_addline(buffer, "unknown_flags(%#x)", global_flags);
+}
+
+static void shader_dump_sync_flags(struct vkd3d_string_buffer *buffer, DWORD sync_flags)
+{
+    if (sync_flags & VKD3DSSF_GROUP_SHARED_MEMORY)
+    {
+        shader_addline(buffer, "_g");
+        sync_flags &= ~VKD3DSSF_GROUP_SHARED_MEMORY;
+    }
+    if (sync_flags & VKD3DSSF_THREAD_GROUP)
+    {
+        shader_addline(buffer, "_t");
+        sync_flags &= ~VKD3DSSF_THREAD_GROUP;
+    }
+
+    if (sync_flags)
+        shader_addline(buffer, "_unknown_flags(%#x)", sync_flags);
+}
+
+static void shader_dump_precise_flags(struct vkd3d_string_buffer *buffer, DWORD flags)
+{
+    if (!(flags & VKD3DSI_PRECISE_XYZW))
+        return;
+
+    shader_addline(buffer, " [precise");
+    if (flags != VKD3DSI_PRECISE_XYZW)
+    {
+        shader_addline(buffer, "(%s%s%s%s)",
+                flags & VKD3DSI_PRECISE_X ? "x" : "",
+                flags & VKD3DSI_PRECISE_Y ? "y" : "",
+                flags & VKD3DSI_PRECISE_Z ? "z" : "",
+                flags & VKD3DSI_PRECISE_W ? "w" : "");
+    }
+    shader_addline(buffer, "]");
+}
+
+static void shader_dump_uav_flags(struct vkd3d_string_buffer *buffer, DWORD uav_flags)
+{
+    if (uav_flags & VKD3DSUF_GLOBALLY_COHERENT)
+    {
+        shader_addline(buffer, "_glc");
+        uav_flags &= ~VKD3DSUF_GLOBALLY_COHERENT;
+    }
+    if (uav_flags & VKD3DSUF_ORDER_PRESERVING_COUNTER)
+    {
+        shader_addline(buffer, "_opc");
+        uav_flags &= ~VKD3DSUF_ORDER_PRESERVING_COUNTER;
+    }
+
+    if (uav_flags)
+        shader_addline(buffer, "_unknown_flags(%#x)", uav_flags);
+}
+
+static void shader_dump_tessellator_domain(struct vkd3d_string_buffer *buffer,
+        enum vkd3d_tessellator_domain domain)
+{
+    shader_addline(buffer, "domain_");
+    switch (domain)
+    {
+        case VKD3D_TESSELLATOR_DOMAIN_LINE:
+            shader_addline(buffer, "isoline");
+            break;
+        case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE:
+            shader_addline(buffer, "tri");
+            break;
+        case VKD3D_TESSELLATOR_DOMAIN_QUAD:
+            shader_addline(buffer, "quad");
+            break;
+        default:
+            shader_addline(buffer, "unknown_tessellator_domain(%#x)", domain);
+            break;
+    }
+}
+
+static void shader_dump_tessellator_output_primitive(struct vkd3d_string_buffer *buffer,
+        enum vkd3d_shader_tessellator_output_primitive output_primitive)
+{
+    shader_addline(buffer, "output_");
+    switch (output_primitive)
+    {
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT:
+            shader_addline(buffer, "point");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE:
+            shader_addline(buffer, "line");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW:
+            shader_addline(buffer, "triangle_cw");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
+            shader_addline(buffer, "triangle_ccw");
+            break;
+        default:
+            shader_addline(buffer, "unknown_tessellator_output_primitive(%#x)", output_primitive);
+            break;
+    }
+}
+
+static void shader_dump_tessellator_partitioning(struct vkd3d_string_buffer *buffer,
+        enum vkd3d_shader_tessellator_partitioning partitioning)
+{
+    shader_addline(buffer, "partitioning_");
+    switch (partitioning)
+    {
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER:
+            shader_addline(buffer, "integer");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2:
+            shader_addline(buffer, "pow2");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
+            shader_addline(buffer, "fractional_odd");
+            break;
+        case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
+            shader_addline(buffer, "fractional_even");
+            break;
+        default:
+            shader_addline(buffer, "unknown_tessellator_partitioning(%#x)", partitioning);
+            break;
+    }
+}
+
+static void shader_dump_shader_input_sysval_semantic(struct vkd3d_string_buffer *buffer,
+        enum vkd3d_shader_input_sysval_semantic semantic)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(shader_input_sysval_semantic_names); ++i)
+    {
+        if (shader_input_sysval_semantic_names[i].sysval_semantic == semantic)
+        {
+            shader_addline(buffer, "%s", shader_input_sysval_semantic_names[i].sysval_name);
+            return;
+        }
+    }
+
+    shader_addline(buffer, "unknown_shader_input_sysval_semantic(%#x)", semantic);
+}
+
+static void shader_dump_resource_type(struct vkd3d_string_buffer *buffer, enum vkd3d_shader_resource_type type)
+{
+    static const char *const resource_type_names[] =
+    {
+        /* VKD3D_SHADER_RESOURCE_NONE                 */ "none",
+        /* VKD3D_SHADER_RESOURCE_BUFFER               */ "buffer",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_1D           */ "texture1d",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_2D           */ "texture2d",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMS         */ "texture2dms",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_3D           */ "texture3d",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBE         */ "texturecube",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY      */ "texture1darray",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY      */ "texture2darray",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY    */ "texture2dmsarray",
+        /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY    */ "texturecubearray",
+    };
+
+    if (type <= ARRAY_SIZE(resource_type_names))
+        shader_addline(buffer, "%s", resource_type_names[type]);
+    else
+        shader_addline(buffer, "unknown");
+}
+
+static void shader_dump_data_type(struct vkd3d_string_buffer *buffer, enum vkd3d_data_type type)
+{
+    static const char *const data_type_names[] =
+    {
+        /* VKD3D_DATA_FLOAT    */ "float",
+        /* VKD3D_DATA_INT      */ "int",
+        /* VKD3D_DATA_RESOURCE */ "resource",
+        /* VKD3D_DATA_SAMPLER  */ "sampler",
+        /* VKD3D_DATA_UAV      */ "uav",
+        /* VKD3D_DATA_UINT     */ "uint",
+        /* VKD3D_DATA_UNORM    */ "unorm",
+        /* VKD3D_DATA_SNORM    */ "snorm",
+        /* VKD3D_DATA_OPAQUE   */ "opaque",
+    };
+    const char *name;
+
+    if (type <= ARRAY_SIZE(data_type_names))
+        name = data_type_names[type];
+    else
+        name = "unknown";
+
+    shader_addline(buffer, "(%s,%s,%s,%s)", name, name, name, name);
+}
+
+static void shader_dump_decl_usage(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_semantic *semantic, unsigned int flags,
+        const struct vkd3d_shader_version *shader_version)
+{
+    shader_addline(buffer, "dcl");
+
+    if (semantic->resource.reg.reg.type == VKD3DSPR_SAMPLER)
+    {
+        switch (semantic->resource_type)
+        {
+            case VKD3D_SHADER_RESOURCE_TEXTURE_2D:
+                shader_addline(buffer, "_2d");
+                break;
+
+            case VKD3D_SHADER_RESOURCE_TEXTURE_3D:
+                shader_addline(buffer, "_3d");
+                break;
+
+            case VKD3D_SHADER_RESOURCE_TEXTURE_CUBE:
+                shader_addline(buffer, "_cube");
+                break;
+
+            default:
+                shader_addline(buffer, "_unknown_resource_type(%#x)", semantic->resource_type);
+                break;
+        }
+    }
+    else if (semantic->resource.reg.reg.type == VKD3DSPR_RESOURCE || semantic->resource.reg.reg.type == VKD3DSPR_UAV)
+    {
+        if (semantic->resource.reg.reg.type == VKD3DSPR_RESOURCE)
+            shader_addline(buffer, "_resource_");
+        else
+            /* non typed UAVs don't go through this code path */
+            shader_addline(buffer, "_uav_typed_");
+
+        shader_dump_resource_type(buffer, semantic->resource_type);
+        if (semantic->resource.reg.reg.type == VKD3DSPR_UAV)
+            shader_dump_uav_flags(buffer, flags);
+        shader_dump_data_type(buffer, semantic->resource_data_type);
+    }
+    else
+    {
+        /* Pixel shaders 3.0 don't have usage semantics. */
+        if (!shader_ver_ge(shader_version, 3, 0) && shader_version->type == VKD3D_SHADER_TYPE_PIXEL)
+            return;
+        else
+            shader_addline(buffer, "_");
+
+        switch (semantic->usage)
+        {
+            case VKD3D_DECL_USAGE_POSITION:
+                shader_addline(buffer, "position%u", semantic->usage_idx);
+                break;
+
+            case VKD3D_DECL_USAGE_BLEND_INDICES:
+                shader_addline(buffer, "blend");
+                break;
+
+            case VKD3D_DECL_USAGE_BLEND_WEIGHT:
+                shader_addline(buffer, "weight");
+                break;
+
+            case VKD3D_DECL_USAGE_NORMAL:
+                shader_addline(buffer, "normal%u", semantic->usage_idx);
+                break;
+
+            case VKD3D_DECL_USAGE_PSIZE:
+                shader_addline(buffer, "psize");
+                break;
+
+            case VKD3D_DECL_USAGE_COLOR:
+                if (!semantic->usage_idx)
+                    shader_addline(buffer, "color");
+                else
+                    shader_addline(buffer, "specular%u", (semantic->usage_idx - 1));
+                break;
+
+            case VKD3D_DECL_USAGE_TEXCOORD:
+                shader_addline(buffer, "texture%u", semantic->usage_idx);
+                break;
+
+            case VKD3D_DECL_USAGE_TANGENT:
+                shader_addline(buffer, "tangent");
+                break;
+
+            case VKD3D_DECL_USAGE_BINORMAL:
+                shader_addline(buffer, "binormal");
+                break;
+
+            case VKD3D_DECL_USAGE_TESS_FACTOR:
+                shader_addline(buffer, "tessfactor");
+                break;
+
+            case VKD3D_DECL_USAGE_POSITIONT:
+                shader_addline(buffer, "positionT%u", semantic->usage_idx);
+                break;
+
+            case VKD3D_DECL_USAGE_FOG:
+                shader_addline(buffer, "fog");
+                break;
+
+            case VKD3D_DECL_USAGE_DEPTH:
+                shader_addline(buffer, "depth");
+                break;
+
+            case VKD3D_DECL_USAGE_SAMPLE:
+                shader_addline(buffer, "sample");
+                break;
+
+            default:
+                shader_addline(buffer, "<unknown_semantic(%#x)>", semantic->usage);
+                FIXME("Unrecognised semantic usage %#x.\n", semantic->usage);
+        }
+    }
+}
+
+static void shader_dump_src_param(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_src_param *param, const struct vkd3d_shader_version *shader_version);
+
+static void shader_dump_register(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_register *reg, const struct vkd3d_shader_version *shader_version)
+{
+    static const char * const rastout_reg_names[] = {"oPos", "oFog", "oPts"};
+    static const char * const misctype_reg_names[] = {"vPos", "vFace"};
+    unsigned int offset = reg->idx[0].offset;
+
+    switch (reg->type)
+    {
+        case VKD3DSPR_TEMP:
+            shader_addline(buffer, "r");
+            break;
+
+        case VKD3DSPR_INPUT:
+            shader_addline(buffer, "v");
+            break;
+
+        case VKD3DSPR_CONST:
+        case VKD3DSPR_CONST2:
+        case VKD3DSPR_CONST3:
+        case VKD3DSPR_CONST4:
+            shader_addline(buffer, "c");
+            offset = shader_get_float_offset(reg->type, offset);
+            break;
+
+        case VKD3DSPR_TEXTURE: /* vs: case VKD3DSPR_ADDR */
+            shader_addline(buffer, "%c", shader_version->type == VKD3D_SHADER_TYPE_PIXEL ? 't' : 'a');
+            break;
+
+        case VKD3DSPR_RASTOUT:
+            shader_addline(buffer, "%s", rastout_reg_names[offset]);
+            break;
+
+        case VKD3DSPR_COLOROUT:
+            shader_addline(buffer, "o");
+            if (!shader_ver_ge(shader_version, 4, 0))
+                shader_addline(buffer, "C");
+            break;
+
+        case VKD3DSPR_DEPTHOUT:
+            shader_addline(buffer, "oDepth");
+            break;
+
+        case VKD3DSPR_DEPTHOUTGE:
+            shader_addline(buffer, "oDepthGE");
+            break;
+
+        case VKD3DSPR_DEPTHOUTLE:
+            shader_addline(buffer, "oDepthLE");
+            break;
+
+        case VKD3DSPR_ATTROUT:
+            shader_addline(buffer, "oD");
+            break;
+
+        case VKD3DSPR_TEXCRDOUT:
+            /* Vertex shaders >= 3.0 use general purpose output registers
+             * (VKD3DSPR_OUTPUT), which can include an address token. */
+            if (shader_ver_ge(shader_version, 3, 0))
+                shader_addline(buffer, "o");
+            else
+                shader_addline(buffer, "oT");
+            break;
+
+        case VKD3DSPR_CONSTINT:
+            shader_addline(buffer, "i");
+            break;
+
+        case VKD3DSPR_CONSTBOOL:
+            shader_addline(buffer, "b");
+            break;
+
+        case VKD3DSPR_LABEL:
+            shader_addline(buffer, "l");
+            break;
+
+        case VKD3DSPR_LOOP:
+            shader_addline(buffer, "aL");
+            break;
+
+        case VKD3DSPR_SAMPLER:
+            shader_addline(buffer, "s");
+            break;
+
+        case VKD3DSPR_MISCTYPE:
+            if (offset > 1)
+            {
+                FIXME("Unhandled misctype register %u.\n", offset);
+                shader_addline(buffer, "<unhandled misctype %#x>", offset);
+            }
+            else
+            {
+                shader_addline(buffer, "%s", misctype_reg_names[offset]);
+            }
+            break;
+
+        case VKD3DSPR_PREDICATE:
+            shader_addline(buffer, "p");
+            break;
+
+        case VKD3DSPR_IMMCONST:
+            shader_addline(buffer, "l");
+            break;
+
+        case VKD3DSPR_CONSTBUFFER:
+            shader_addline(buffer, "cb");
+            break;
+
+        case VKD3DSPR_IMMCONSTBUFFER:
+            shader_addline(buffer, "icb");
+            break;
+
+        case VKD3DSPR_PRIMID:
+            shader_addline(buffer, "primID");
+            break;
+
+        case VKD3DSPR_NULL:
+            shader_addline(buffer, "null");
+            break;
+
+        case VKD3DSPR_RASTERIZER:
+            shader_addline(buffer, "rasterizer");
+            break;
+
+        case VKD3DSPR_RESOURCE:
+            shader_addline(buffer, "t");
+            break;
+
+        case VKD3DSPR_UAV:
+            shader_addline(buffer, "u");
+            break;
+
+        case VKD3DSPR_OUTPOINTID:
+            shader_addline(buffer, "vOutputControlPointID");
+            break;
+
+        case VKD3DSPR_FORKINSTID:
+            shader_addline(buffer, "vForkInstanceId");
+            break;
+
+        case VKD3DSPR_JOININSTID:
+            shader_addline(buffer, "vJoinInstanceId");
+            break;
+
+        case VKD3DSPR_INCONTROLPOINT:
+            shader_addline(buffer, "vicp");
+            break;
+
+        case VKD3DSPR_OUTCONTROLPOINT:
+            shader_addline(buffer, "vocp");
+            break;
+
+        case VKD3DSPR_PATCHCONST:
+            shader_addline(buffer, "vpc");
+            break;
+
+        case VKD3DSPR_TESSCOORD:
+            shader_addline(buffer, "vDomainLocation");
+            break;
+
+        case VKD3DSPR_GROUPSHAREDMEM:
+            shader_addline(buffer, "g");
+            break;
+
+        case VKD3DSPR_THREADID:
+            shader_addline(buffer, "vThreadID");
+            break;
+
+        case VKD3DSPR_THREADGROUPID:
+            shader_addline(buffer, "vThreadGroupID");
+            break;
+
+        case VKD3DSPR_LOCALTHREADID:
+            shader_addline(buffer, "vThreadIDInGroup");
+            break;
+
+        case VKD3DSPR_LOCALTHREADINDEX:
+            shader_addline(buffer, "vThreadIDInGroupFlattened");
+            break;
+
+        case VKD3DSPR_IDXTEMP:
+            shader_addline(buffer, "x");
+            break;
+
+        case VKD3DSPR_STREAM:
+            shader_addline(buffer, "m");
+            break;
+
+        case VKD3DSPR_FUNCTIONBODY:
+            shader_addline(buffer, "fb");
+            break;
+
+        case VKD3DSPR_FUNCTIONPOINTER:
+            shader_addline(buffer, "fp");
+            break;
+
+        case VKD3DSPR_COVERAGE:
+            shader_addline(buffer, "vCoverage");
+            break;
+
+        case VKD3DSPR_SAMPLEMASK:
+            shader_addline(buffer, "oMask");
+            break;
+
+        case VKD3DSPR_GSINSTID:
+            shader_addline(buffer, "vGSInstanceID");
+            break;
+
+        default:
+            shader_addline(buffer, "<unhandled_rtype(%#x)>", reg->type);
+            break;
+    }
+
+    if (reg->type == VKD3DSPR_IMMCONST)
+    {
+        shader_addline(buffer, "(");
+        switch (reg->immconst_type)
+        {
+            case VKD3D_IMMCONST_SCALAR:
+                switch (reg->data_type)
+                {
+                    case VKD3D_DATA_FLOAT:
+                        shader_addline(buffer, "%.8e", reg->u.immconst_float[0]);
+                        break;
+                    case VKD3D_DATA_INT:
+                        shader_addline(buffer, "%d", reg->u.immconst_uint[0]);
+                        break;
+                    case VKD3D_DATA_RESOURCE:
+                    case VKD3D_DATA_SAMPLER:
+                    case VKD3D_DATA_UINT:
+                        shader_addline(buffer, "%u", reg->u.immconst_uint[0]);
+                        break;
+                    default:
+                        shader_addline(buffer, "<unhandled data type %#x>", reg->data_type);
+                        break;
+                }
+                break;
+
+            case VKD3D_IMMCONST_VEC4:
+                switch (reg->data_type)
+                {
+                    case VKD3D_DATA_FLOAT:
+                        shader_addline(buffer, "%.8e, %.8e, %.8e, %.8e",
+                                reg->u.immconst_float[0], reg->u.immconst_float[1],
+                                reg->u.immconst_float[2], reg->u.immconst_float[3]);
+                        break;
+                    case VKD3D_DATA_INT:
+                        shader_addline(buffer, "%d, %d, %d, %d",
+                                reg->u.immconst_uint[0], reg->u.immconst_uint[1],
+                                reg->u.immconst_uint[2], reg->u.immconst_uint[3]);
+                        break;
+                    case VKD3D_DATA_RESOURCE:
+                    case VKD3D_DATA_SAMPLER:
+                    case VKD3D_DATA_UINT:
+                        shader_addline(buffer, "%u, %u, %u, %u",
+                                reg->u.immconst_uint[0], reg->u.immconst_uint[1],
+                                reg->u.immconst_uint[2], reg->u.immconst_uint[3]);
+                        break;
+                    default:
+                        shader_addline(buffer, "<unhandled data type %#x>", reg->data_type);
+                        break;
+                }
+                break;
+
+            default:
+                shader_addline(buffer, "<unhandled immconst_type %#x>", reg->immconst_type);
+                break;
+        }
+        shader_addline(buffer, ")");
+    }
+    else if (reg->type != VKD3DSPR_RASTOUT
+            && reg->type != VKD3DSPR_MISCTYPE
+            && reg->type != VKD3DSPR_NULL)
+    {
+        if (offset != ~0u)
+        {
+            bool printbrackets = reg->idx[0].rel_addr
+                || reg->type == VKD3DSPR_INCONTROLPOINT
+                || reg->type == VKD3DSPR_IMMCONSTBUFFER
+                || ((shader_version->type == VKD3D_SHADER_TYPE_GEOMETRY
+                            || shader_version->type == VKD3D_SHADER_TYPE_HULL)
+                        && reg->type == VKD3DSPR_INPUT);
+
+            if (printbrackets)
+                shader_addline(buffer, "[");
+            if (reg->idx[0].rel_addr)
+            {
+                shader_dump_src_param(buffer, reg->idx[0].rel_addr, shader_version);
+                shader_addline(buffer, " + ");
+            }
+            shader_addline(buffer, "%u", offset);
+            if (printbrackets)
+                shader_addline(buffer, "]");
+
+            /* For CBs in sm < 5.1 we move the buffer offset from idx[1] to idx[2]
+             * to normalise it with 5.1.
+             * Here we should ignore it if it's a CB in sm < 5.1. */
+            if (reg->idx[1].offset != ~0u &&
+                    (reg->type != VKD3DSPR_CONSTBUFFER || shader_ver_ge(shader_version, 5, 1)))
+            {
+                shader_addline(buffer, "[");
+                if (reg->idx[1].rel_addr)
+                {
+                    shader_dump_src_param(buffer, reg->idx[1].rel_addr, shader_version);
+                    shader_addline(buffer, " + ");
+                }
+                shader_addline(buffer, "%u]", reg->idx[1].offset);
+            }
+
+            if (reg->idx[2].offset != ~0u)
+            {
+                shader_addline(buffer, "[");
+                if (reg->idx[2].rel_addr)
+                {
+                    shader_dump_src_param(buffer, reg->idx[2].rel_addr, shader_version);
+                    shader_addline(buffer, " + ");
+                }
+                shader_addline(buffer, "%u]", reg->idx[2].offset);
+            }
+        }
+
+        if (reg->type == VKD3DSPR_FUNCTIONPOINTER)
+            shader_addline(buffer, "[%u]", reg->u.fp_body_idx);
+    }
+}
+
+static void shader_dump_dst_param(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_dst_param *param, const struct vkd3d_shader_version *shader_version)
+{
+    DWORD write_mask = param->write_mask;
+
+    shader_dump_register(buffer, &param->reg, shader_version);
+
+    if (write_mask)
+    {
+        static const char write_mask_chars[] = "xyzw";
+
+        shader_addline(buffer, ".");
+        if (write_mask & VKD3DSP_WRITEMASK_0)
+            shader_addline(buffer, "%c", write_mask_chars[0]);
+        if (write_mask & VKD3DSP_WRITEMASK_1)
+            shader_addline(buffer, "%c", write_mask_chars[1]);
+        if (write_mask & VKD3DSP_WRITEMASK_2)
+            shader_addline(buffer, "%c", write_mask_chars[2]);
+        if (write_mask & VKD3DSP_WRITEMASK_3)
+            shader_addline(buffer, "%c", write_mask_chars[3]);
+    }
+}
+
+static void shader_dump_src_param(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_src_param *param, const struct vkd3d_shader_version *shader_version)
+{
+    enum vkd3d_shader_src_modifier src_modifier = param->modifiers;
+    DWORD swizzle = param->swizzle;
+
+    if (src_modifier == VKD3DSPSM_NEG
+            || src_modifier == VKD3DSPSM_BIASNEG
+            || src_modifier == VKD3DSPSM_SIGNNEG
+            || src_modifier == VKD3DSPSM_X2NEG
+            || src_modifier == VKD3DSPSM_ABSNEG)
+        shader_addline(buffer, "-");
+    else if (src_modifier == VKD3DSPSM_COMP)
+        shader_addline(buffer, "1-");
+    else if (src_modifier == VKD3DSPSM_NOT)
+        shader_addline(buffer, "!");
+
+    if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG)
+        shader_addline(buffer, "|");
+
+    shader_dump_register(buffer, &param->reg, shader_version);
+
+    switch (src_modifier)
+    {
+        case VKD3DSPSM_NONE:    break;
+        case VKD3DSPSM_NEG:     break;
+        case VKD3DSPSM_NOT:     break;
+        case VKD3DSPSM_BIAS:    shader_addline(buffer, "_bias"); break;
+        case VKD3DSPSM_BIASNEG: shader_addline(buffer, "_bias"); break;
+        case VKD3DSPSM_SIGN:    shader_addline(buffer, "_bx2"); break;
+        case VKD3DSPSM_SIGNNEG: shader_addline(buffer, "_bx2"); break;
+        case VKD3DSPSM_COMP:    break;
+        case VKD3DSPSM_X2:      shader_addline(buffer, "_x2"); break;
+        case VKD3DSPSM_X2NEG:   shader_addline(buffer, "_x2"); break;
+        case VKD3DSPSM_DZ:      shader_addline(buffer, "_dz"); break;
+        case VKD3DSPSM_DW:      shader_addline(buffer, "_dw"); break;
+        case VKD3DSPSM_ABSNEG:
+        case VKD3DSPSM_ABS:     /* handled later */ break;
+        default:                  shader_addline(buffer, "_unknown_modifier(%#x)", src_modifier);
+    }
+
+    if (param->reg.type != VKD3DSPR_IMMCONST && param->reg.type != VKD3DSPR_SAMPLER)
+    {
+        static const char swizzle_chars[] = "xyzw";
+        DWORD swizzle_x = (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(0)) & VKD3D_SHADER_SWIZZLE_MASK;
+        DWORD swizzle_y = (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(1)) & VKD3D_SHADER_SWIZZLE_MASK;
+        DWORD swizzle_z = (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(2)) & VKD3D_SHADER_SWIZZLE_MASK;
+        DWORD swizzle_w = (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(3)) & VKD3D_SHADER_SWIZZLE_MASK;
+
+        if (swizzle_x == swizzle_y
+                && swizzle_x == swizzle_z
+                && swizzle_x == swizzle_w)
+        {
+            shader_addline(buffer, ".%c", swizzle_chars[swizzle_x]);
+        }
+        else
+        {
+            shader_addline(buffer, ".%c%c%c%c", swizzle_chars[swizzle_x], swizzle_chars[swizzle_y],
+                    swizzle_chars[swizzle_z], swizzle_chars[swizzle_w]);
+        }
+    }
+    if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG)
+        shader_addline(buffer, "|");
+}
+
+static void shader_dump_ins_modifiers(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_dst_param *dst)
+{
+    DWORD mmask = dst->modifiers;
+
+    switch (dst->shift)
+    {
+        case 0: break;
+        case 13: shader_addline(buffer, "_d8"); break;
+        case 14: shader_addline(buffer, "_d4"); break;
+        case 15: shader_addline(buffer, "_d2"); break;
+        case 1: shader_addline(buffer, "_x2"); break;
+        case 2: shader_addline(buffer, "_x4"); break;
+        case 3: shader_addline(buffer, "_x8"); break;
+        default: shader_addline(buffer, "_unhandled_shift(%d)", dst->shift); break;
+    }
+
+    if (mmask & VKD3DSPDM_SATURATE)         shader_addline(buffer, "_sat");
+    if (mmask & VKD3DSPDM_PARTIALPRECISION) shader_addline(buffer, "_pp");
+    if (mmask & VKD3DSPDM_MSAMPCENTROID)    shader_addline(buffer, "_centroid");
+
+    mmask &= ~(VKD3DSPDM_SATURATE | VKD3DSPDM_PARTIALPRECISION | VKD3DSPDM_MSAMPCENTROID);
+    if (mmask) FIXME("Unrecognised modifier %#x.\n", mmask);
+}
+
+static void shader_dump_primitive_type(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_primitive_type *primitive_type)
+{
+    switch (primitive_type->type)
+    {
+        case VKD3D_PT_UNDEFINED:
+            shader_addline(buffer, "undefined");
+            break;
+        case VKD3D_PT_POINTLIST:
+            shader_addline(buffer, "pointlist");
+            break;
+        case VKD3D_PT_LINELIST:
+            shader_addline(buffer, "linelist");
+            break;
+        case VKD3D_PT_LINESTRIP:
+            shader_addline(buffer, "linestrip");
+            break;
+        case VKD3D_PT_TRIANGLELIST:
+            shader_addline(buffer, "trianglelist");
+            break;
+        case VKD3D_PT_TRIANGLESTRIP:
+            shader_addline(buffer, "trianglestrip");
+            break;
+        case VKD3D_PT_TRIANGLEFAN:
+            shader_addline(buffer, "trianglefan");
+            break;
+        case VKD3D_PT_LINELIST_ADJ:
+            shader_addline(buffer, "linelist_adj");
+            break;
+        case VKD3D_PT_LINESTRIP_ADJ:
+            shader_addline(buffer, "linestrip_adj");
+            break;
+        case VKD3D_PT_TRIANGLELIST_ADJ:
+            shader_addline(buffer, "trianglelist_adj");
+            break;
+        case VKD3D_PT_TRIANGLESTRIP_ADJ:
+            shader_addline(buffer, "trianglestrip_adj");
+            break;
+        case VKD3D_PT_PATCH:
+            shader_addline(buffer, "patch%u", primitive_type->patch_vertex_count);
+            break;
+        default:
+            shader_addline(buffer, "<unrecognized_primitive_type %#x>", primitive_type->type);
+            break;
+    }
+}
+
+static void shader_dump_interpolation_mode(struct vkd3d_string_buffer *buffer,
+        enum vkd3d_shader_interpolation_mode interpolation_mode)
+{
+    switch (interpolation_mode)
+    {
+        case VKD3DSIM_CONSTANT:
+            shader_addline(buffer, "constant");
+            break;
+        case VKD3DSIM_LINEAR:
+            shader_addline(buffer, "linear");
+            break;
+        case VKD3DSIM_LINEAR_CENTROID:
+            shader_addline(buffer, "linear centroid");
+            break;
+        case VKD3DSIM_LINEAR_NOPERSPECTIVE:
+            shader_addline(buffer, "linear noperspective");
+            break;
+        case VKD3DSIM_LINEAR_SAMPLE:
+            shader_addline(buffer, "linear sample");
+            break;
+        case VKD3DSIM_LINEAR_NOPERSPECTIVE_CENTROID:
+            shader_addline(buffer, "linear noperspective centroid");
+            break;
+        case VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE:
+            shader_addline(buffer, "linear noperspective sample");
+            break;
+        default:
+            shader_addline(buffer, "<unrecognized_interpolation_mode %#x>", interpolation_mode);
+            break;
+    }
+}
+
+const char *shader_get_type_prefix(enum vkd3d_shader_type type)
+{
+    switch (type)
+    {
+        case VKD3D_SHADER_TYPE_VERTEX:
+            return "vs";
+
+        case VKD3D_SHADER_TYPE_HULL:
+            return "hs";
+
+        case VKD3D_SHADER_TYPE_DOMAIN:
+            return "ds";
+
+        case VKD3D_SHADER_TYPE_GEOMETRY:
+            return "gs";
+
+        case VKD3D_SHADER_TYPE_PIXEL:
+            return "ps";
+
+        case VKD3D_SHADER_TYPE_COMPUTE:
+            return "cs";
+
+        default:
+            FIXME("Unhandled shader type %#x.\n", type);
+            return "unknown";
+    }
+}
+
+static void shader_dump_instruction_flags(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_version *shader_version)
+{
+    switch (ins->handler_idx)
+    {
+        case VKD3DSIH_BREAKP:
+        case VKD3DSIH_CONTINUEP:
+        case VKD3DSIH_IF:
+        case VKD3DSIH_RETP:
+        case VKD3DSIH_TEXKILL:
+            switch (ins->flags)
+            {
+                case VKD3D_SHADER_CONDITIONAL_OP_NZ: shader_addline(buffer, "_nz"); break;
+                case VKD3D_SHADER_CONDITIONAL_OP_Z:  shader_addline(buffer, "_z"); break;
+                default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); break;
+            }
+            break;
+
+        case VKD3DSIH_IFC:
+        case VKD3DSIH_BREAKC:
+            switch (ins->flags)
+            {
+                case VKD3D_SHADER_REL_OP_GT: shader_addline(buffer, "_gt"); break;
+                case VKD3D_SHADER_REL_OP_EQ: shader_addline(buffer, "_eq"); break;
+                case VKD3D_SHADER_REL_OP_GE: shader_addline(buffer, "_ge"); break;
+                case VKD3D_SHADER_REL_OP_LT: shader_addline(buffer, "_lt"); break;
+                case VKD3D_SHADER_REL_OP_NE: shader_addline(buffer, "_ne"); break;
+                case VKD3D_SHADER_REL_OP_LE: shader_addline(buffer, "_le"); break;
+                default: shader_addline(buffer, "_(%u)", ins->flags);
+            }
+            break;
+
+        case VKD3DSIH_RESINFO:
+            switch (ins->flags)
+            {
+                case VKD3DSI_NONE: break;
+                case VKD3DSI_RESINFO_RCP_FLOAT: shader_addline(buffer, "_rcpFloat"); break;
+                case VKD3DSI_RESINFO_UINT: shader_addline(buffer, "_uint"); break;
+                default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags);
+            }
+            break;
+
+        case VKD3DSIH_SAMPLE_INFO:
+            switch (ins->flags)
+            {
+                case VKD3DSI_NONE: break;
+                case VKD3DSI_SAMPLE_INFO_UINT: shader_addline(buffer, "_uint"); break;
+                default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags);
+            }
+            break;
+
+        case VKD3DSIH_SYNC:
+            shader_dump_sync_flags(buffer, ins->flags);
+            break;
+
+        case VKD3DSIH_TEX:
+            if (shader_ver_ge(shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT))
+                shader_addline(buffer, "p");
+            break;
+
+        default:
+            shader_dump_precise_flags(buffer, ins->flags);
+            break;
+    }
+}
+
+static void shader_dump_register_space(struct vkd3d_string_buffer *buffer,
+        unsigned int register_space, const struct vkd3d_shader_version *shader_version)
+{
+    if (shader_ver_ge(shader_version, 5, 1))
+        shader_addline(buffer, ", space=%u", register_space);
+}
+
+static void shader_dump_instruction(struct vkd3d_string_buffer *buffer,
+        const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_version *shader_version)
+{
+    unsigned int i;
+
+    switch (ins->handler_idx)
+    {
+        case VKD3DSIH_DCL:
+        case VKD3DSIH_DCL_UAV_TYPED:
+            shader_dump_decl_usage(buffer, &ins->declaration.semantic, ins->flags, shader_version);
+            shader_dump_ins_modifiers(buffer, &ins->declaration.semantic.resource.reg);
+            shader_addline(buffer, " ");
+            shader_dump_register(buffer, &ins->declaration.semantic.resource.reg.reg, shader_version);
+            shader_dump_register_space(buffer, ins->declaration.semantic.resource.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_CONSTANT_BUFFER:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_register(buffer, &ins->declaration.cb.src.reg, shader_version);
+            if (shader_ver_ge(shader_version, 5, 1))
+                shader_addline(buffer, "[%u]", ins->declaration.cb.size);
+            shader_addline(buffer, ", %s",
+                    ins->flags & VKD3DSI_INDEXED_DYNAMIC ? "dynamicIndexed" : "immediateIndexed");
+            shader_dump_register_space(buffer, ins->declaration.cb.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_FUNCTION_BODY:
+            shader_addline(buffer, "%s fb%u",
+                    shader_opcode_names[ins->handler_idx], ins->declaration.index);
+            break;
+
+        case VKD3DSIH_DCL_FUNCTION_TABLE:
+            shader_addline(buffer, "%s ft%u = {...}",
+                    shader_opcode_names[ins->handler_idx], ins->declaration.index);
+            break;
+
+        case VKD3DSIH_DCL_GLOBAL_FLAGS:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_global_flags(buffer, ins->flags);
+            break;
+
+        case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
+            shader_addline(buffer, "%s %.8e", shader_opcode_names[ins->handler_idx],
+                    ins->declaration.max_tessellation_factor);
+            break;
+
+        case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER:
+            shader_addline(buffer, "%s {\n", shader_opcode_names[ins->handler_idx]);
+            for (i = 0; i < ins->declaration.icb->vec4_count; ++i)
+            {
+                shader_addline(buffer, "    {0x%08x, 0x%08x, 0x%08x, 0x%08x},\n",
+                        ins->declaration.icb->data[4 * i + 0],
+                        ins->declaration.icb->data[4 * i + 1],
+                        ins->declaration.icb->data[4 * i + 2],
+                        ins->declaration.icb->data[4 * i + 3]);
+            }
+            shader_addline(buffer, "}");
+            break;
+
+        case VKD3DSIH_DCL_INDEX_RANGE:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.index_range.dst, shader_version);
+            shader_addline(buffer, " %u", ins->declaration.index_range.register_count);
+            break;
+
+        case VKD3DSIH_DCL_INDEXABLE_TEMP:
+            shader_addline(buffer, "%s x%u[%u], %u", shader_opcode_names[ins->handler_idx],
+                    ins->declaration.indexable_temp.register_idx,
+                    ins->declaration.indexable_temp.register_size,
+                    ins->declaration.indexable_temp.component_count);
+            break;
+
+        case VKD3DSIH_DCL_INPUT_PS:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_interpolation_mode(buffer, ins->flags);
+            shader_addline(buffer, " ");
+            shader_dump_dst_param(buffer, &ins->declaration.dst, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_INPUT_PS_SGV:
+        case VKD3DSIH_DCL_INPUT_SGV:
+        case VKD3DSIH_DCL_INPUT_SIV:
+        case VKD3DSIH_DCL_OUTPUT_SIV:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.register_semantic.reg, shader_version);
+            shader_addline(buffer, ", ");
+            shader_dump_shader_input_sysval_semantic(buffer, ins->declaration.register_semantic.sysval_semantic);
+            break;
+
+        case VKD3DSIH_DCL_INPUT_PS_SIV:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_interpolation_mode(buffer, ins->flags);
+            shader_addline(buffer, " ");
+            shader_dump_dst_param(buffer, &ins->declaration.register_semantic.reg, shader_version);
+            shader_addline(buffer, ", ");
+            shader_dump_shader_input_sysval_semantic(buffer, ins->declaration.register_semantic.sysval_semantic);
+            break;
+
+        case VKD3DSIH_DCL_INPUT:
+        case VKD3DSIH_DCL_OUTPUT:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.dst, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_INPUT_PRIMITIVE:
+        case VKD3DSIH_DCL_OUTPUT_TOPOLOGY:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_primitive_type(buffer, &ins->declaration.primitive_type);
+            break;
+
+        case VKD3DSIH_DCL_INTERFACE:
+            shader_addline(buffer, "%s fp%u[%u][%u] = {...}",
+                    shader_opcode_names[ins->handler_idx], ins->declaration.fp.index,
+                    ins->declaration.fp.array_size, ins->declaration.fp.body_count);
+            break;
+
+        case VKD3DSIH_DCL_RESOURCE_RAW:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.raw_resource.resource.reg, shader_version);
+            shader_dump_register_space(buffer, ins->declaration.raw_resource.resource.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.structured_resource.resource.reg, shader_version);
+            shader_addline(buffer, ", %u", ins->declaration.structured_resource.byte_stride);
+            shader_dump_register_space(buffer,
+                    ins->declaration.structured_resource.resource.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_SAMPLER:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_register(buffer, &ins->declaration.sampler.src.reg, shader_version);
+            if (ins->flags == VKD3DSI_SAMPLER_COMPARISON_MODE)
+                shader_addline(buffer, ", comparisonMode");
+            shader_dump_register_space(buffer, ins->declaration.sampler.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_TEMPS:
+        case VKD3DSIH_DCL_GS_INSTANCES:
+        case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
+        case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
+        case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT:
+        case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT:
+        case VKD3DSIH_DCL_VERTICES_OUT:
+            shader_addline(buffer, "%s %u", shader_opcode_names[ins->handler_idx], ins->declaration.count);
+            break;
+
+        case VKD3DSIH_DCL_TESSELLATOR_DOMAIN:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_tessellator_domain(buffer, ins->declaration.tessellator_domain);
+            break;
+
+        case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_tessellator_output_primitive(buffer, ins->declaration.tessellator_output_primitive);
+            break;
+
+        case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_tessellator_partitioning(buffer, ins->declaration.tessellator_partitioning);
+            break;
+
+        case VKD3DSIH_DCL_TGSM_RAW:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.tgsm_raw.reg, shader_version);
+            shader_addline(buffer, ", %u", ins->declaration.tgsm_raw.byte_count);
+            break;
+
+        case VKD3DSIH_DCL_TGSM_STRUCTURED:
+            shader_addline(buffer, "%s ", shader_opcode_names[ins->handler_idx]);
+            shader_dump_dst_param(buffer, &ins->declaration.tgsm_structured.reg, shader_version);
+            shader_addline(buffer, ", %u, %u", ins->declaration.tgsm_structured.byte_stride,
+                    ins->declaration.tgsm_structured.structure_count);
+            break;
+
+        case VKD3DSIH_DCL_THREAD_GROUP:
+            shader_addline(buffer, "%s %u, %u, %u", shader_opcode_names[ins->handler_idx],
+                    ins->declaration.thread_group_size.x,
+                    ins->declaration.thread_group_size.y,
+                    ins->declaration.thread_group_size.z);
+            break;
+
+        case VKD3DSIH_DCL_UAV_RAW:
+            shader_addline(buffer, "%s", shader_opcode_names[ins->handler_idx]);
+            shader_dump_uav_flags(buffer, ins->flags);
+            shader_addline(buffer, " ");
+            shader_dump_dst_param(buffer, &ins->declaration.raw_resource.resource.reg, shader_version);
+            shader_dump_register_space(buffer, ins->declaration.raw_resource.resource.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DCL_UAV_STRUCTURED:
+            shader_addline(buffer, "%s", shader_opcode_names[ins->handler_idx]);
+            shader_dump_uav_flags(buffer, ins->flags);
+            shader_addline(buffer, " ");
+            shader_dump_dst_param(buffer, &ins->declaration.structured_resource.resource.reg, shader_version);
+            shader_addline(buffer, ", %u", ins->declaration.structured_resource.byte_stride);
+            shader_dump_register_space(buffer,
+                    ins->declaration.structured_resource.resource.register_space, shader_version);
+            break;
+
+        case VKD3DSIH_DEF:
+            shader_addline(buffer, "def c%u = %.8e, %.8e, %.8e, %.8e",
+                    shader_get_float_offset(ins->dst[0].reg.type, ins->dst[0].reg.idx[0].offset),
+                    ins->src[0].reg.u.immconst_float[0], ins->src[0].reg.u.immconst_float[1],
+                    ins->src[0].reg.u.immconst_float[2], ins->src[0].reg.u.immconst_float[3]);
+            break;
+
+        case VKD3DSIH_DEFI:
+            shader_addline(buffer, "defi i%u = %d, %d, %d, %d", ins->dst[0].reg.idx[0].offset,
+                    ins->src[0].reg.u.immconst_uint[0], ins->src[0].reg.u.immconst_uint[1],
+                    ins->src[0].reg.u.immconst_uint[2], ins->src[0].reg.u.immconst_uint[3]);
+            break;
+
+        case VKD3DSIH_DEFB:
+            shader_addline(buffer, "defb b%u = %s",
+                    ins->dst[0].reg.idx[0].offset, ins->src[0].reg.u.immconst_uint[0] ? "true" : "false");
+            break;
+
+        default:
+            if (ins->predicate)
+            {
+                shader_addline(buffer, "(");
+                shader_dump_src_param(buffer, ins->predicate, shader_version);
+                shader_addline(buffer, ") ");
+            }
+
+            /* PixWin marks instructions with the coissue flag with a '+' */
+            if (ins->coissue)
+                shader_addline(buffer, "+");
+
+            shader_addline(buffer, "%s", shader_opcode_names[ins->handler_idx]);
+
+            shader_dump_instruction_flags(buffer, ins, shader_version);
+            if (vkd3d_shader_instruction_has_texel_offset(ins))
+            {
+                shader_addline(buffer, "(%d,%d,%d)",
+                        ins->texel_offset.u, ins->texel_offset.v, ins->texel_offset.w);
+            }
+
+            if (ins->resource_type != VKD3D_SHADER_RESOURCE_NONE)
+            {
+                shader_addline(buffer, "(");
+                shader_dump_resource_type(buffer, ins->resource_type);
+                shader_addline(buffer, ")");
+            }
+
+            if (ins->resource_data_type != VKD3D_DATA_FLOAT)
+                shader_dump_data_type(buffer, ins->resource_data_type);
+
+            for (i = 0; i < ins->dst_count; ++i)
+            {
+                shader_dump_ins_modifiers(buffer, &ins->dst[i]);
+                shader_addline(buffer, !i ? " " : ", ");
+                shader_dump_dst_param(buffer, &ins->dst[i], shader_version);
+            }
+
+            /* Other source tokens */
+            for (i = ins->dst_count; i < (ins->dst_count + ins->src_count); ++i)
+            {
+                shader_addline(buffer, !i ? " " : ", ");
+                shader_dump_src_param(buffer, &ins->src[i - ins->dst_count], shader_version);
+            }
+            break;
+    }
+
+    shader_addline(buffer, "\n");
+}
+
+void vkd3d_shader_trace(void *data)
+{
+    struct vkd3d_shader_version shader_version;
+    struct vkd3d_string_buffer buffer;
+    const char *p, *q;
+    const DWORD *ptr;
+
+    if (!vkd3d_string_buffer_init(&buffer))
+    {
+        ERR("Failed to initialize string buffer.\n");
+        return;
+    }
+
+    shader_sm4_read_header(data, &ptr, &shader_version);
+    shader_addline(&buffer, "%s_%u_%u\n",
+            shader_get_type_prefix(shader_version.type), shader_version.major, shader_version.minor);
+
+    while (!shader_sm4_is_end(data, &ptr))
+    {
+        struct vkd3d_shader_instruction ins;
+
+        shader_sm4_read_instruction(data, &ptr, &ins);
+        if (ins.handler_idx == VKD3DSIH_INVALID)
+        {
+            WARN("Skipping unrecognized instruction.\n");
+            shader_addline(&buffer, "<unrecognized instruction>\n");
+            continue;
+        }
+
+        shader_dump_instruction(&buffer, &ins, &shader_version);
+    }
+
+    for (p = buffer.buffer; *p; p = q)
+    {
+        if (!(q = strstr(p, "\n")))
+            q = p + strlen(p);
+        else
+            ++q;
+        TRACE("    %.*s", (int)(q - p), p);
+    }
+
+    vkd3d_string_buffer_cleanup(&buffer);
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader.map b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader.map
new file mode 100644
index 00000000000..1937131b48b
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader.map
@@ -0,0 +1,21 @@
+VKD3D_1_0
+{
+global:
+    vkd3d_shader_compile;
+    vkd3d_shader_convert_root_signature;
+    vkd3d_shader_find_signature_element;
+    vkd3d_shader_free_messages;
+    vkd3d_shader_free_root_signature;
+    vkd3d_shader_free_scan_descriptor_info;
+    vkd3d_shader_free_shader_code;
+    vkd3d_shader_free_shader_signature;
+    vkd3d_shader_get_supported_source_types;
+    vkd3d_shader_get_supported_target_types;
+    vkd3d_shader_get_version;
+    vkd3d_shader_parse_input_signature;
+    vkd3d_shader_parse_root_signature;
+    vkd3d_shader_scan;
+    vkd3d_shader_serialize_root_signature;
+
+local: *;
+};
diff --git a/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
new file mode 100644
index 00000000000..16d895ff0a4
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright 2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_shader_private.h"
+#include "vkd3d_version.h"
+
+#include <stdio.h>
+
+VKD3D_DEBUG_ENV_NAME("VKD3D_SHADER_DEBUG");
+
+static void vkd3d_string_buffer_clear(struct vkd3d_string_buffer *buffer)
+{
+    buffer->buffer[0] = '\0';
+    buffer->content_size = 0;
+}
+
+bool vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer)
+{
+    buffer->buffer_size = 32;
+    if (!(buffer->buffer = vkd3d_malloc(buffer->buffer_size)))
+    {
+        ERR("Failed to allocate shader buffer memory.\n");
+        return false;
+    }
+
+    vkd3d_string_buffer_clear(buffer);
+    return true;
+}
+
+void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer)
+{
+    vkd3d_free(buffer->buffer);
+}
+
+static bool vkd3d_string_buffer_resize(struct vkd3d_string_buffer *buffer, int rc)
+{
+    unsigned int new_buffer_size = buffer->buffer_size * 2;
+    char *new_buffer;
+
+    while (rc > 0 && (unsigned int)rc >= new_buffer_size - buffer->content_size)
+        new_buffer_size *= 2;
+    if (!(new_buffer = vkd3d_realloc(buffer->buffer, new_buffer_size)))
+    {
+        ERR("Failed to grow buffer.\n");
+        buffer->buffer[buffer->content_size] = '\0';
+        return false;
+    }
+    buffer->buffer = new_buffer;
+    buffer->buffer_size = new_buffer_size;
+    return true;
+}
+
+int vkd3d_string_buffer_vprintf(struct vkd3d_string_buffer *buffer, const char *format, va_list args)
+{
+    unsigned int rem;
+    va_list a;
+    int rc;
+
+    for (;;)
+    {
+        rem = buffer->buffer_size - buffer->content_size;
+        va_copy(a, args);
+        rc = vsnprintf(&buffer->buffer[buffer->content_size], rem, format, a);
+        va_end(a);
+        if (rc >= 0 && (unsigned int)rc < rem)
+        {
+            buffer->content_size += rc;
+            return 0;
+        }
+
+        if (!vkd3d_string_buffer_resize(buffer, rc))
+            return -1;
+    }
+}
+
+static int VKD3D_PRINTF_FUNC(2, 3) vkd3d_string_buffer_printf(struct vkd3d_string_buffer *buffer,
+        const char *format, ...)
+{
+    va_list args;
+    int ret;
+
+    va_start(args, format);
+    ret = vkd3d_string_buffer_vprintf(buffer, format, args);
+    va_end(args);
+
+    return ret;
+}
+
+static void vkd3d_string_buffer_trace_(const struct vkd3d_string_buffer *buffer, const char *function)
+{
+    const char *p, *q;
+
+    if (!TRACE_ON())
+        return;
+
+    for (p = buffer->buffer; *p; p = q)
+    {
+        if (!(q = strstr(p, "\n")))
+            q = p + strlen(p);
+        else
+            ++q;
+        vkd3d_dbg_printf(VKD3D_DBG_LEVEL_TRACE, function, "%.*s", (int)(q - p), p);
+    }
+}
+
+bool vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context,
+        enum vkd3d_shader_log_level log_level, const char *source_name)
+{
+    context->log_level = log_level;
+    context->source_name = source_name ? source_name : "<anonymous>";
+    context->line = 0;
+    context->column = 0;
+
+    return vkd3d_string_buffer_init(&context->messages);
+}
+
+void vkd3d_shader_message_context_cleanup(struct vkd3d_shader_message_context *context)
+{
+    vkd3d_string_buffer_cleanup(&context->messages);
+}
+
+void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_message_context *context,
+        const char *function)
+{
+    vkd3d_string_buffer_trace_(&context->messages, function);
+}
+
+char *vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context)
+{
+    char *messages;
+
+    if ((messages = vkd3d_malloc(context->messages.content_size + 1)))
+        memcpy(messages, context->messages.buffer, context->messages.content_size + 1);
+
+    return messages;
+}
+
+void vkd3d_shader_verror(struct vkd3d_shader_message_context *context,
+        enum vkd3d_shader_error error, const char *format, va_list args)
+{
+    if (context->log_level < VKD3D_SHADER_LOG_ERROR)
+        return;
+
+    if (context->line)
+        vkd3d_string_buffer_printf(&context->messages, "%s:%u:%u: E%04u: ",
+                context->source_name, context->line, context->column, error);
+    else
+        vkd3d_string_buffer_printf(&context->messages, "%s: E%04u: ", context->source_name, error);
+    vkd3d_string_buffer_vprintf(&context->messages, format, args);
+    vkd3d_string_buffer_printf(&context->messages, "\n");
+}
+
+void vkd3d_shader_error(struct vkd3d_shader_message_context *context,
+        enum vkd3d_shader_error error, const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    vkd3d_shader_verror(context, error, format, args);
+    va_end(args);
+}
+
+static void vkd3d_shader_dump_blob(const char *path, const char *prefix, const void *data, size_t size)
+{
+    static int shader_id = 0;
+    char filename[1024];
+    unsigned int id;
+    FILE *f;
+
+    id = InterlockedIncrement(&shader_id) - 1;
+
+    snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s-%u.dxbc", path, prefix, id);
+    if ((f = fopen(filename, "wb")))
+    {
+        if (fwrite(data, 1, size, f) != size)
+            ERR("Failed to write shader to %s.\n", filename);
+        if (fclose(f))
+            ERR("Failed to close stream %s.\n", filename);
+    }
+    else
+    {
+        ERR("Failed to open %s for dumping shader.\n", filename);
+    }
+}
+
+static void vkd3d_shader_dump_shader(enum vkd3d_shader_type type, const struct vkd3d_shader_code *shader)
+{
+    static bool enabled = true;
+    const char *path;
+
+    if (!enabled)
+        return;
+
+    if (!(path = getenv("VKD3D_SHADER_DUMP_PATH")))
+    {
+        enabled = false;
+        return;
+    }
+
+    vkd3d_shader_dump_blob(path, shader_get_type_prefix(type), shader->code, shader->size);
+}
+
+struct vkd3d_shader_parser
+{
+    struct vkd3d_shader_desc shader_desc;
+    struct vkd3d_shader_version shader_version;
+    void *data;
+    const DWORD *ptr;
+};
+
+static int vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser,
+        const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context)
+{
+    struct vkd3d_shader_desc *shader_desc = &parser->shader_desc;
+    int ret;
+
+    if ((ret = shader_extract_from_dxbc(dxbc->code, dxbc->size, message_context, shader_desc)) < 0)
+    {
+        WARN("Failed to extract shader, vkd3d result %d.\n", ret);
+        return ret;
+    }
+
+    if (!(parser->data = shader_sm4_init(shader_desc->byte_code,
+            shader_desc->byte_code_size, &shader_desc->output_signature)))
+    {
+        WARN("Failed to initialize shader parser.\n");
+        free_shader_desc(shader_desc);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    shader_sm4_read_header(parser->data, &parser->ptr, &parser->shader_version);
+    return VKD3D_OK;
+}
+
+static void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser)
+{
+    shader_sm4_free(parser->data);
+    free_shader_desc(&parser->shader_desc);
+}
+
+static int vkd3d_shader_validate_compile_info(const struct vkd3d_shader_compile_info *compile_info)
+{
+    const enum vkd3d_shader_source_type *source_types;
+    const enum vkd3d_shader_target_type *target_types;
+    unsigned int count, i;
+
+    if (compile_info->type != VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO)
+    {
+        WARN("Invalid structure type %#x.\n", compile_info->type);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    source_types = vkd3d_shader_get_supported_source_types(&count);
+    for (i = 0; i < count; ++i)
+    {
+        if (source_types[i] == compile_info->source_type)
+            break;
+    }
+    if (i == count)
+    {
+        WARN("Invalid shader source type %#x.\n", compile_info->source_type);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    target_types = vkd3d_shader_get_supported_target_types(compile_info->source_type, &count);
+    for (i = 0; i < count; ++i)
+    {
+        if (target_types[i] == compile_info->target_type)
+            break;
+    }
+    if (i == count)
+    {
+        WARN("Invalid shader target type %#x.\n", compile_info->target_type);
+        return VKD3D_ERROR_INVALID_ARGUMENT;
+    }
+
+    return VKD3D_OK;
+}
+
+void vkd3d_shader_free_messages(char *messages)
+{
+    TRACE("messages %p.\n", messages);
+
+    vkd3d_free(messages);
+}
+
+int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
+        struct vkd3d_shader_code *out, char **messages)
+{
+    struct vkd3d_shader_scan_descriptor_info scan_descriptor_info;
+    struct vkd3d_shader_message_context message_context;
+    struct vkd3d_shader_instruction instruction;
+    struct vkd3d_shader_compile_info scan_info;
+    struct vkd3d_dxbc_compiler *spirv_compiler;
+    struct vkd3d_shader_parser parser;
+    int ret;
+
+    TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages);
+
+    if (messages)
+        *messages = NULL;
+
+    if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
+        return ret;
+
+    scan_info = *compile_info;
+    scan_descriptor_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO;
+    scan_descriptor_info.next = scan_info.next;
+    scan_info.next = &scan_descriptor_info;
+
+    if ((ret = vkd3d_shader_scan(&scan_info, messages)) < 0)
+        return ret;
+    if (messages)
+    {
+        vkd3d_shader_free_messages(*messages);
+        *messages = NULL;
+    }
+
+    if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name))
+        return VKD3D_ERROR;
+    if ((ret = vkd3d_shader_parser_init(&parser, &compile_info->source, &message_context)) < 0)
+        goto done;
+
+    vkd3d_shader_dump_shader(parser.shader_version.type, &compile_info->source);
+
+    if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&parser.shader_version,
+            &parser.shader_desc, compile_info, &scan_descriptor_info, &message_context)))
+    {
+        ERR("Failed to create DXBC compiler.\n");
+        vkd3d_shader_parser_destroy(&parser);
+        ret = VKD3D_ERROR;
+        goto done;
+    }
+
+    message_context.line = 2; /* Line 1 is the version token. */
+    message_context.column = 1;
+    while (!shader_sm4_is_end(parser.data, &parser.ptr))
+    {
+        shader_sm4_read_instruction(parser.data, &parser.ptr, &instruction);
+
+        if (instruction.handler_idx == VKD3DSIH_INVALID)
+        {
+            WARN("Encountered unrecognized or invalid instruction.\n");
+            ret = VKD3D_ERROR_INVALID_SHADER;
+            break;
+        }
+
+        if ((ret = vkd3d_dxbc_compiler_handle_instruction(spirv_compiler, &instruction)) < 0)
+            break;
+        ++message_context.line;
+    }
+
+    if (ret >= 0)
+        ret = vkd3d_dxbc_compiler_generate_spirv(spirv_compiler, compile_info, out);
+
+    vkd3d_dxbc_compiler_destroy(spirv_compiler);
+    vkd3d_shader_parser_destroy(&parser);
+done:
+    vkd3d_shader_message_context_trace_messages(&message_context);
+    if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&message_context)))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+    vkd3d_shader_message_context_cleanup(&message_context);
+    vkd3d_shader_free_scan_descriptor_info(&scan_descriptor_info);
+    return ret;
+}
+
+struct vkd3d_shader_scan_context
+{
+    struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
+    size_t descriptors_size;
+
+    struct vkd3d_shader_message_context message_context;
+
+    struct vkd3d_shader_cf_info
+    {
+        enum
+        {
+            VKD3D_SHADER_BLOCK_IF,
+            VKD3D_SHADER_BLOCK_LOOP,
+            VKD3D_SHADER_BLOCK_SWITCH,
+        } type;
+        bool inside_block;
+        bool has_default;
+    } *cf_info;
+    size_t cf_info_size;
+    size_t cf_info_count;
+
+    struct
+    {
+        unsigned int id;
+        unsigned int descriptor_idx;
+    } *uav_ranges;
+    size_t uav_ranges_size;
+    size_t uav_range_count;
+};
+
+static bool vkd3d_shader_scan_context_init(struct vkd3d_shader_scan_context *context,
+        struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info,
+        enum vkd3d_shader_log_level log_level, const char *source_name)
+{
+    memset(context, 0, sizeof(*context));
+    context->scan_descriptor_info = scan_descriptor_info;
+    return vkd3d_shader_message_context_init(&context->message_context, log_level, source_name);
+}
+
+static void vkd3d_shader_scan_context_cleanup(struct vkd3d_shader_scan_context *context)
+{
+    vkd3d_free(context->uav_ranges);
+    vkd3d_free(context->cf_info);
+    vkd3d_shader_message_context_cleanup(&context->message_context);
+}
+
+static struct vkd3d_shader_cf_info *vkd3d_shader_scan_get_current_cf_info(struct vkd3d_shader_scan_context *context)
+{
+    if (!context->cf_info_count)
+        return NULL;
+    return &context->cf_info[context->cf_info_count - 1];
+}
+
+static struct vkd3d_shader_cf_info *vkd3d_shader_scan_push_cf_info(struct vkd3d_shader_scan_context *context)
+{
+    struct vkd3d_shader_cf_info *cf_info;
+
+    if (!vkd3d_array_reserve((void **)&context->cf_info, &context->cf_info_size,
+            context->cf_info_count + 1, sizeof(*context->cf_info)))
+    {
+        ERR("Failed to allocate UAV range.\n");
+        return false;
+    }
+
+    cf_info = &context->cf_info[context->cf_info_count++];
+    memset(cf_info, 0, sizeof(*cf_info));
+
+    return cf_info;
+}
+
+static void vkd3d_shader_scan_pop_cf_info(struct vkd3d_shader_scan_context *context)
+{
+    assert(context->cf_info_count);
+
+    --context->cf_info_count;
+}
+
+static struct vkd3d_shader_cf_info *vkd3d_shader_scan_find_innermost_breakable_cf_info(
+        struct vkd3d_shader_scan_context *context)
+{
+    size_t count = context->cf_info_count;
+    struct vkd3d_shader_cf_info *cf_info;
+
+    while (count)
+    {
+        cf_info = &context->cf_info[--count];
+        if (cf_info->type == VKD3D_SHADER_BLOCK_LOOP
+                || cf_info->type == VKD3D_SHADER_BLOCK_SWITCH)
+            return cf_info;
+    }
+
+    return NULL;
+}
+
+static struct vkd3d_shader_cf_info *vkd3d_shader_scan_find_innermost_loop_cf_info(
+        struct vkd3d_shader_scan_context *context)
+{
+    size_t count = context->cf_info_count;
+    struct vkd3d_shader_cf_info *cf_info;
+
+    while (count)
+    {
+        cf_info = &context->cf_info[--count];
+        if (cf_info->type == VKD3D_SHADER_BLOCK_LOOP)
+            return cf_info;
+    }
+
+    return NULL;
+}
+
+static struct vkd3d_shader_descriptor_info *vkd3d_shader_scan_get_uav_descriptor_info(
+        const struct vkd3d_shader_scan_context *context, unsigned int range_id)
+{
+    unsigned int i;
+
+    for (i = 0; i < context->uav_range_count; ++i)
+    {
+        if (context->uav_ranges[i].id == range_id)
+            return &context->scan_descriptor_info->descriptors[context->uav_ranges[i].descriptor_idx];
+    }
+
+    return NULL;
+}
+
+static bool vkd3d_shader_instruction_is_uav_read(const struct vkd3d_shader_instruction *instruction)
+{
+    enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx = instruction->handler_idx;
+    return (VKD3DSIH_ATOMIC_AND <= handler_idx && handler_idx <= VKD3DSIH_ATOMIC_XOR)
+            || (VKD3DSIH_IMM_ATOMIC_ALLOC <= handler_idx && handler_idx <= VKD3DSIH_IMM_ATOMIC_XOR)
+            || handler_idx == VKD3DSIH_LD_UAV_TYPED
+            || (handler_idx == VKD3DSIH_LD_RAW && instruction->src[1].reg.type == VKD3DSPR_UAV)
+            || (handler_idx == VKD3DSIH_LD_STRUCTURED && instruction->src[2].reg.type == VKD3DSPR_UAV);
+}
+
+static void vkd3d_shader_scan_record_uav_read(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_register *reg)
+{
+    struct vkd3d_shader_descriptor_info *d;
+
+    if (!context->scan_descriptor_info)
+        return;
+
+    d = vkd3d_shader_scan_get_uav_descriptor_info(context, reg->idx[0].offset);
+    d->flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ;
+}
+
+static bool vkd3d_shader_instruction_is_uav_counter(const struct vkd3d_shader_instruction *instruction)
+{
+    enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx = instruction->handler_idx;
+    return handler_idx == VKD3DSIH_IMM_ATOMIC_ALLOC
+            || handler_idx == VKD3DSIH_IMM_ATOMIC_CONSUME;
+}
+
+static void vkd3d_shader_scan_record_uav_counter(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_register *reg)
+{
+    struct vkd3d_shader_descriptor_info *d;
+
+    if (!context->scan_descriptor_info)
+        return;
+
+    d = vkd3d_shader_scan_get_uav_descriptor_info(context, reg->idx[0].offset);
+    d->flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER;
+}
+
+static bool vkd3d_shader_scan_add_descriptor(struct vkd3d_shader_scan_context *context,
+        enum vkd3d_shader_descriptor_type type, unsigned int register_space, unsigned int register_index,
+        enum vkd3d_shader_resource_type resource_type, enum vkd3d_shader_resource_data_type resource_data_type,
+        unsigned int flags)
+{
+    struct vkd3d_shader_scan_descriptor_info *info = context->scan_descriptor_info;
+    struct vkd3d_shader_descriptor_info *d;
+
+    if (!vkd3d_array_reserve((void **)&info->descriptors, &context->descriptors_size,
+            info->descriptor_count + 1, sizeof(*info->descriptors)))
+    {
+        ERR("Failed to allocate descriptor info.\n");
+        return false;
+    }
+
+    d = &info->descriptors[info->descriptor_count];
+    d->type = type;
+    d->register_space = register_space;
+    d->register_index = register_index;
+    d->resource_type = resource_type;
+    d->resource_data_type = resource_data_type;
+    d->flags = flags;
+    d->count = 1;
+    ++info->descriptor_count;
+
+    return true;
+}
+
+static bool vkd3d_shader_scan_add_uav_range(struct vkd3d_shader_scan_context *context,
+        unsigned int id, unsigned int descriptor_idx)
+{
+    if (!vkd3d_array_reserve((void **)&context->uav_ranges, &context->uav_ranges_size,
+            context->uav_range_count + 1, sizeof(*context->uav_ranges)))
+    {
+        ERR("Failed to allocate UAV range.\n");
+        return false;
+    }
+
+    context->uav_ranges[context->uav_range_count].id = id;
+    context->uav_ranges[context->uav_range_count].descriptor_idx = descriptor_idx;
+    ++context->uav_range_count;
+
+    return true;
+}
+
+static void vkd3d_shader_scan_constant_buffer_declaration(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb;
+
+    if (!context->scan_descriptor_info)
+        return;
+
+    vkd3d_shader_scan_add_descriptor(context, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, cb->register_space,
+            cb->register_index, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0);
+}
+
+static void vkd3d_shader_scan_sampler_declaration(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_sampler *sampler = &instruction->declaration.sampler;
+    unsigned int flags;
+
+    if (!context->scan_descriptor_info)
+        return;
+
+    if (instruction->flags & VKD3DSI_SAMPLER_COMPARISON_MODE)
+        flags = VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE;
+    else
+        flags = 0;
+    vkd3d_shader_scan_add_descriptor(context, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, sampler->register_space,
+            sampler->register_index, VKD3D_SHADER_RESOURCE_NONE, VKD3D_SHADER_RESOURCE_DATA_UINT, flags);
+}
+
+static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type,
+        enum vkd3d_shader_resource_data_type resource_data_type)
+{
+    enum vkd3d_shader_descriptor_type type;
+
+    if (!context->scan_descriptor_info)
+        return;
+
+    if (resource->reg.reg.type == VKD3DSPR_UAV)
+        type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+    else
+        type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+    vkd3d_shader_scan_add_descriptor(context, type, resource->register_space,
+            resource->register_index, resource_type, resource_data_type, 0);
+    if (type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+        vkd3d_shader_scan_add_uav_range(context, resource->reg.reg.idx[0].offset,
+                context->scan_descriptor_info->descriptor_count - 1);
+}
+
+static void vkd3d_shader_scan_typed_resource_declaration(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    const struct vkd3d_shader_semantic *semantic = &instruction->declaration.semantic;
+    enum vkd3d_shader_resource_data_type resource_data_type;
+
+    switch (semantic->resource_data_type)
+    {
+        case VKD3D_DATA_UNORM:
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_UNORM;
+            break;
+        case VKD3D_DATA_SNORM:
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_SNORM;
+            break;
+        case VKD3D_DATA_INT:
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_INT;
+            break;
+        case VKD3D_DATA_UINT:
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_UINT;
+            break;
+        case VKD3D_DATA_FLOAT:
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_FLOAT;
+            break;
+        default:
+            ERR("Invalid resource data type %#x.\n", semantic->resource_data_type);
+            resource_data_type = VKD3D_SHADER_RESOURCE_DATA_FLOAT;
+            break;
+    }
+    vkd3d_shader_scan_resource_declaration(context, &semantic->resource,
+            semantic->resource_type, resource_data_type);
+}
+
+static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *context,
+        const struct vkd3d_shader_instruction *instruction)
+{
+    struct vkd3d_shader_cf_info *cf_info;
+    unsigned int i;
+
+    switch (instruction->handler_idx)
+    {
+        case VKD3DSIH_DCL_CONSTANT_BUFFER:
+            vkd3d_shader_scan_constant_buffer_declaration(context, instruction);
+            break;
+        case VKD3DSIH_DCL_SAMPLER:
+            vkd3d_shader_scan_sampler_declaration(context, instruction);
+            break;
+        case VKD3DSIH_DCL:
+        case VKD3DSIH_DCL_UAV_TYPED:
+            vkd3d_shader_scan_typed_resource_declaration(context, instruction);
+            break;
+        case VKD3DSIH_DCL_RESOURCE_RAW:
+        case VKD3DSIH_DCL_UAV_RAW:
+            vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.raw_resource.resource,
+                    VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT);
+            break;
+        case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
+        case VKD3DSIH_DCL_UAV_STRUCTURED:
+            vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.structured_resource.resource,
+                    VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT);
+            break;
+        case VKD3DSIH_IF:
+            cf_info = vkd3d_shader_scan_push_cf_info(context);
+            cf_info->type = VKD3D_SHADER_BLOCK_IF;
+            cf_info->inside_block = true;
+            break;
+        case VKD3DSIH_ELSE:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_IF)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘else’ instruction without corresponding ‘if’ block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            cf_info->inside_block = true;
+            break;
+        case VKD3DSIH_ENDIF:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_IF)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘endif’ instruction without corresponding ‘if’ block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            vkd3d_shader_scan_pop_cf_info(context);
+            break;
+        case VKD3DSIH_LOOP:
+            cf_info = vkd3d_shader_scan_push_cf_info(context);
+            cf_info->type = VKD3D_SHADER_BLOCK_LOOP;
+            break;
+        case VKD3DSIH_ENDLOOP:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_LOOP)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘endloop’ instruction without corresponding ‘loop’ block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            vkd3d_shader_scan_pop_cf_info(context);
+            break;
+        case VKD3DSIH_SWITCH:
+            cf_info = vkd3d_shader_scan_push_cf_info(context);
+            cf_info->type = VKD3D_SHADER_BLOCK_SWITCH;
+            break;
+        case VKD3DSIH_ENDSWITCH:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context))
+                    || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH || cf_info->inside_block)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘endswitch’ instruction without corresponding ‘switch’ block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            vkd3d_shader_scan_pop_cf_info(context);
+            break;
+        case VKD3DSIH_CASE:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context))
+                    || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘case’ instruction outside switch block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            cf_info->inside_block = true;
+            break;
+        case VKD3DSIH_DEFAULT:
+            if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context))
+                    || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘default’ instruction outside switch block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            if (cf_info->has_default)
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered duplicate ‘default’ instruction inside the current switch block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            cf_info->inside_block = true;
+            cf_info->has_default = true;
+            break;
+        case VKD3DSIH_BREAK:
+            if (!(cf_info = vkd3d_shader_scan_find_innermost_breakable_cf_info(context)))
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘break’ instruction outside breakable block.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            cf_info->inside_block = false;
+            break;
+        case VKD3DSIH_BREAKP:
+            if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context)))
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘breakp’ instruction outside loop.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            break;
+        case VKD3DSIH_CONTINUE:
+            if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context)))
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘continue’ instruction outside loop.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            cf_info->inside_block = false;
+            break;
+        case VKD3DSIH_CONTINUEP:
+            if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context)))
+            {
+                vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF,
+                        "Encountered ‘continue’ instruction outside loop.");
+                return VKD3D_ERROR_INVALID_SHADER;
+            }
+            break;
+        case VKD3DSIH_RET:
+            if (context->cf_info_count)
+                context->cf_info[context->cf_info_count - 1].inside_block = false;
+            break;
+        default:
+            break;
+    }
+
+    if (vkd3d_shader_instruction_is_uav_read(instruction))
+    {
+        for (i = 0; i < instruction->dst_count; ++i)
+        {
+            if (instruction->dst[i].reg.type == VKD3DSPR_UAV)
+                vkd3d_shader_scan_record_uav_read(context, &instruction->dst[i].reg);
+        }
+        for (i = 0; i < instruction->src_count; ++i)
+        {
+            if (instruction->src[i].reg.type == VKD3DSPR_UAV)
+                vkd3d_shader_scan_record_uav_read(context, &instruction->src[i].reg);
+        }
+    }
+
+    if (vkd3d_shader_instruction_is_uav_counter(instruction))
+        vkd3d_shader_scan_record_uav_counter(context, &instruction->src[0].reg);
+
+    return VKD3D_OK;
+}
+
+int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages)
+{
+    struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
+    struct vkd3d_shader_message_context *message_context;
+    struct vkd3d_shader_instruction instruction;
+    struct vkd3d_shader_scan_context context;
+    struct vkd3d_shader_parser parser;
+    int ret;
+
+    TRACE("compile_info %p, messages %p.\n", compile_info, messages);
+
+    if (messages)
+        *messages = NULL;
+
+    if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
+        return ret;
+
+    if ((scan_descriptor_info = vkd3d_find_struct(compile_info->next, SCAN_DESCRIPTOR_INFO)))
+    {
+        scan_descriptor_info->descriptors = NULL;
+        scan_descriptor_info->descriptor_count = 0;
+    }
+
+    if (!vkd3d_shader_scan_context_init(&context, scan_descriptor_info,
+            compile_info->log_level, compile_info->source_name))
+        return VKD3D_ERROR;
+    message_context = &context.message_context;
+
+    if ((ret = vkd3d_shader_parser_init(&parser, &compile_info->source, message_context)) < 0)
+    {
+        vkd3d_shader_message_context_trace_messages(message_context);
+        if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(message_context)))
+            ret = VKD3D_ERROR_OUT_OF_MEMORY;
+        vkd3d_shader_scan_context_cleanup(&context);
+        return ret;
+    }
+
+    if (TRACE_ON())
+        vkd3d_shader_trace(parser.data);
+
+    message_context->line = 2; /* Line 1 is the version token. */
+    message_context->column = 1;
+    while (!shader_sm4_is_end(parser.data, &parser.ptr))
+    {
+        shader_sm4_read_instruction(parser.data, &parser.ptr, &instruction);
+
+        if (instruction.handler_idx == VKD3DSIH_INVALID)
+        {
+            WARN("Encountered unrecognized or invalid instruction.\n");
+            if (scan_descriptor_info)
+                vkd3d_shader_free_scan_descriptor_info(scan_descriptor_info);
+            ret = VKD3D_ERROR_INVALID_SHADER;
+            goto done;
+        }
+
+        if ((ret = vkd3d_shader_scan_instruction(&context, &instruction)) < 0)
+        {
+            if (scan_descriptor_info)
+                vkd3d_shader_free_scan_descriptor_info(scan_descriptor_info);
+            goto done;
+        }
+        ++message_context->line;
+    }
+
+    ret = VKD3D_OK;
+
+done:
+    vkd3d_shader_message_context_trace_messages(message_context);
+    if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(message_context)))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+    vkd3d_shader_scan_context_cleanup(&context);
+    vkd3d_shader_parser_destroy(&parser);
+    return ret;
+}
+
+void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info)
+{
+    TRACE("scan_descriptor_info %p.\n", scan_descriptor_info);
+
+    vkd3d_free(scan_descriptor_info->descriptors);
+}
+
+void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *shader_code)
+{
+    TRACE("shader_code %p.\n", shader_code);
+
+    vkd3d_free((void *)shader_code->code);
+}
+
+static void vkd3d_shader_free_root_signature_v_1_0(struct vkd3d_shader_root_signature_desc *root_signature)
+{
+    unsigned int i;
+
+    for (i = 0; i < root_signature->parameter_count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter *parameter = &root_signature->parameters[i];
+
+        if (parameter->parameter_type == VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            vkd3d_free((void *)parameter->u.descriptor_table.descriptor_ranges);
+    }
+    vkd3d_free((void *)root_signature->parameters);
+    vkd3d_free((void *)root_signature->static_samplers);
+
+    memset(root_signature, 0, sizeof(*root_signature));
+}
+
+static void vkd3d_shader_free_root_signature_v_1_1(struct vkd3d_shader_root_signature_desc1 *root_signature)
+{
+    unsigned int i;
+
+    for (i = 0; i < root_signature->parameter_count; ++i)
+    {
+        const struct vkd3d_shader_root_parameter1 *parameter = &root_signature->parameters[i];
+
+        if (parameter->parameter_type == VKD3D_SHADER_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            vkd3d_free((void *)parameter->u.descriptor_table.descriptor_ranges);
+    }
+    vkd3d_free((void *)root_signature->parameters);
+    vkd3d_free((void *)root_signature->static_samplers);
+
+    memset(root_signature, 0, sizeof(*root_signature));
+}
+
+void vkd3d_shader_free_root_signature(struct vkd3d_shader_versioned_root_signature_desc *desc)
+{
+    TRACE("desc %p.\n", desc);
+
+    if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+    {
+        vkd3d_shader_free_root_signature_v_1_0(&desc->u.v_1_0);
+    }
+    else if (desc->version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        vkd3d_shader_free_root_signature_v_1_1(&desc->u.v_1_1);
+    }
+    else if (desc->version)
+    {
+        FIXME("Unknown version %#x.\n", desc->version);
+        return;
+    }
+
+    desc->version = 0;
+}
+
+int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_signature *signature, char **messages)
+{
+    struct vkd3d_shader_message_context message_context;
+    int ret;
+
+    TRACE("dxbc {%p, %zu}, signature %p, messages %p.\n", dxbc->code, dxbc->size, signature, messages);
+
+    if (messages)
+        *messages = NULL;
+    if (!vkd3d_shader_message_context_init(&message_context, VKD3D_SHADER_LOG_INFO, NULL))
+        return VKD3D_ERROR;
+
+    ret = shader_parse_input_signature(dxbc->code, dxbc->size, &message_context, signature);
+    vkd3d_shader_message_context_trace_messages(&message_context);
+    if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&message_context)))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+
+    vkd3d_shader_message_context_cleanup(&message_context);
+
+    return ret;
+}
+
+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;
+    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 (!ascii_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;
+}
+
+const char *vkd3d_shader_get_version(unsigned int *major, unsigned int *minor)
+{
+    int x, y;
+
+    TRACE("major %p, minor %p.\n", major, minor);
+
+    if (major || minor)
+    {
+        vkd3d_parse_version(PACKAGE_VERSION, &x, &y);
+        if (major)
+            *major = x;
+        if (minor)
+            *minor = y;
+    }
+
+    return "vkd3d-shader " PACKAGE_VERSION VKD3D_VCS_ID;
+}
+
+const enum vkd3d_shader_source_type *vkd3d_shader_get_supported_source_types(unsigned int *count)
+{
+    static const enum vkd3d_shader_source_type types[] =
+    {
+        VKD3D_SHADER_SOURCE_DXBC_TPF,
+    };
+
+    TRACE("count %p.\n", count);
+
+    *count = ARRAY_SIZE(types);
+    return types;
+}
+
+const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types(
+        enum vkd3d_shader_source_type source_type, unsigned int *count)
+{
+    static const enum vkd3d_shader_target_type dxbc_tpf_types[] =
+    {
+        VKD3D_SHADER_TARGET_SPIRV_BINARY,
+#ifdef HAVE_SPIRV_TOOLS
+        VKD3D_SHADER_TARGET_SPIRV_TEXT,
+#endif
+    };
+
+    TRACE("source_type %#x, count %p.\n", source_type, count);
+
+    switch (source_type)
+    {
+        case VKD3D_SHADER_SOURCE_DXBC_TPF:
+            *count = ARRAY_SIZE(dxbc_tpf_types);
+            return dxbc_tpf_types;
+
+        default:
+            *count = 0;
+            return NULL;
+    }
+}
diff --git a/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
new file mode 100644
index 00000000000..00b2441e559
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -0,0 +1,989 @@
+/*
+ * Copyright 2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2002-2003 The wine-d3d team
+ * Copyright 2002-2003 2004 Jason Edmeades
+ * Copyright 2002-2003 Raphael Junqueira
+ * Copyright 2005 Oliver Stieber
+ * Copyright 2006 Stefan Dösinger
+ * Copyright 2006-2011, 2013 Stefan Dösinger for CodeWeavers
+ * Copyright 2007 Henri Verbeet
+ * Copyright 2008-2009 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_SHADER_PRIVATE_H
+#define __VKD3D_SHADER_PRIVATE_H
+
+#define NONAMELESSUNION
+#include "vkd3d_common.h"
+#include "vkd3d_memory.h"
+#include "vkd3d_shader.h"
+#include "list.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <string.h>
+
+#define VKD3D_VEC4_SIZE 4
+
+enum vkd3d_shader_error
+{
+    VKD3D_SHADER_ERROR_DXBC_INVALID_SIZE                = 1,
+    VKD3D_SHADER_ERROR_DXBC_INVALID_MAGIC               = 2,
+    VKD3D_SHADER_ERROR_DXBC_INVALID_CHECKSUM            = 3,
+    VKD3D_SHADER_ERROR_DXBC_INVALID_VERSION             = 4,
+    VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_OFFSET        = 5,
+    VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_SIZE          = 6,
+
+    VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF                = 1000,
+
+    VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND = 2000,
+    VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE        = 2001,
+    VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING   = 2002,
+
+    VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY                 = 3000,
+    VKD3D_SHADER_ERROR_RS_INVALID_VERSION               = 3001,
+    VKD3D_SHADER_ERROR_RS_INVALID_ROOT_PARAMETER_TYPE   = 3002,
+    VKD3D_SHADER_ERROR_RS_INVALID_DESCRIPTOR_RANGE_TYPE = 3003,
+    VKD3D_SHADER_ERROR_RS_MIXED_DESCRIPTOR_RANGE_TYPES  = 3004,
+};
+
+enum VKD3D_SHADER_INSTRUCTION_HANDLER
+{
+    VKD3DSIH_ABS,
+    VKD3DSIH_ADD,
+    VKD3DSIH_AND,
+    VKD3DSIH_ATOMIC_AND,
+    VKD3DSIH_ATOMIC_CMP_STORE,
+    VKD3DSIH_ATOMIC_IADD,
+    VKD3DSIH_ATOMIC_IMAX,
+    VKD3DSIH_ATOMIC_IMIN,
+    VKD3DSIH_ATOMIC_OR,
+    VKD3DSIH_ATOMIC_UMAX,
+    VKD3DSIH_ATOMIC_UMIN,
+    VKD3DSIH_ATOMIC_XOR,
+    VKD3DSIH_BEM,
+    VKD3DSIH_BFI,
+    VKD3DSIH_BFREV,
+    VKD3DSIH_BREAK,
+    VKD3DSIH_BREAKC,
+    VKD3DSIH_BREAKP,
+    VKD3DSIH_BUFINFO,
+    VKD3DSIH_CALL,
+    VKD3DSIH_CALLNZ,
+    VKD3DSIH_CASE,
+    VKD3DSIH_CMP,
+    VKD3DSIH_CND,
+    VKD3DSIH_CONTINUE,
+    VKD3DSIH_CONTINUEP,
+    VKD3DSIH_COUNTBITS,
+    VKD3DSIH_CRS,
+    VKD3DSIH_CUT,
+    VKD3DSIH_CUT_STREAM,
+    VKD3DSIH_DCL,
+    VKD3DSIH_DCL_CONSTANT_BUFFER,
+    VKD3DSIH_DCL_FUNCTION_BODY,
+    VKD3DSIH_DCL_FUNCTION_TABLE,
+    VKD3DSIH_DCL_GLOBAL_FLAGS,
+    VKD3DSIH_DCL_GS_INSTANCES,
+    VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT,
+    VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT,
+    VKD3DSIH_DCL_HS_MAX_TESSFACTOR,
+    VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER,
+    VKD3DSIH_DCL_INDEX_RANGE,
+    VKD3DSIH_DCL_INDEXABLE_TEMP,
+    VKD3DSIH_DCL_INPUT,
+    VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT,
+    VKD3DSIH_DCL_INPUT_PRIMITIVE,
+    VKD3DSIH_DCL_INPUT_PS,
+    VKD3DSIH_DCL_INPUT_PS_SGV,
+    VKD3DSIH_DCL_INPUT_PS_SIV,
+    VKD3DSIH_DCL_INPUT_SGV,
+    VKD3DSIH_DCL_INPUT_SIV,
+    VKD3DSIH_DCL_INTERFACE,
+    VKD3DSIH_DCL_OUTPUT,
+    VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT,
+    VKD3DSIH_DCL_OUTPUT_SIV,
+    VKD3DSIH_DCL_OUTPUT_TOPOLOGY,
+    VKD3DSIH_DCL_RESOURCE_RAW,
+    VKD3DSIH_DCL_RESOURCE_STRUCTURED,
+    VKD3DSIH_DCL_SAMPLER,
+    VKD3DSIH_DCL_STREAM,
+    VKD3DSIH_DCL_TEMPS,
+    VKD3DSIH_DCL_TESSELLATOR_DOMAIN,
+    VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE,
+    VKD3DSIH_DCL_TESSELLATOR_PARTITIONING,
+    VKD3DSIH_DCL_TGSM_RAW,
+    VKD3DSIH_DCL_TGSM_STRUCTURED,
+    VKD3DSIH_DCL_THREAD_GROUP,
+    VKD3DSIH_DCL_UAV_RAW,
+    VKD3DSIH_DCL_UAV_STRUCTURED,
+    VKD3DSIH_DCL_UAV_TYPED,
+    VKD3DSIH_DCL_VERTICES_OUT,
+    VKD3DSIH_DEF,
+    VKD3DSIH_DEFAULT,
+    VKD3DSIH_DEFB,
+    VKD3DSIH_DEFI,
+    VKD3DSIH_DIV,
+    VKD3DSIH_DP2,
+    VKD3DSIH_DP2ADD,
+    VKD3DSIH_DP3,
+    VKD3DSIH_DP4,
+    VKD3DSIH_DST,
+    VKD3DSIH_DSX,
+    VKD3DSIH_DSX_COARSE,
+    VKD3DSIH_DSX_FINE,
+    VKD3DSIH_DSY,
+    VKD3DSIH_DSY_COARSE,
+    VKD3DSIH_DSY_FINE,
+    VKD3DSIH_ELSE,
+    VKD3DSIH_EMIT,
+    VKD3DSIH_EMIT_STREAM,
+    VKD3DSIH_ENDIF,
+    VKD3DSIH_ENDLOOP,
+    VKD3DSIH_ENDREP,
+    VKD3DSIH_ENDSWITCH,
+    VKD3DSIH_EQ,
+    VKD3DSIH_EVAL_CENTROID,
+    VKD3DSIH_EVAL_SAMPLE_INDEX,
+    VKD3DSIH_EXP,
+    VKD3DSIH_EXPP,
+    VKD3DSIH_F16TOF32,
+    VKD3DSIH_F32TOF16,
+    VKD3DSIH_FCALL,
+    VKD3DSIH_FIRSTBIT_HI,
+    VKD3DSIH_FIRSTBIT_LO,
+    VKD3DSIH_FIRSTBIT_SHI,
+    VKD3DSIH_FRC,
+    VKD3DSIH_FTOI,
+    VKD3DSIH_FTOU,
+    VKD3DSIH_GATHER4,
+    VKD3DSIH_GATHER4_C,
+    VKD3DSIH_GATHER4_PO,
+    VKD3DSIH_GATHER4_PO_C,
+    VKD3DSIH_GE,
+    VKD3DSIH_HS_CONTROL_POINT_PHASE,
+    VKD3DSIH_HS_DECLS,
+    VKD3DSIH_HS_FORK_PHASE,
+    VKD3DSIH_HS_JOIN_PHASE,
+    VKD3DSIH_IADD,
+    VKD3DSIH_IBFE,
+    VKD3DSIH_IEQ,
+    VKD3DSIH_IF,
+    VKD3DSIH_IFC,
+    VKD3DSIH_IGE,
+    VKD3DSIH_ILT,
+    VKD3DSIH_IMAD,
+    VKD3DSIH_IMAX,
+    VKD3DSIH_IMIN,
+    VKD3DSIH_IMM_ATOMIC_ALLOC,
+    VKD3DSIH_IMM_ATOMIC_AND,
+    VKD3DSIH_IMM_ATOMIC_CMP_EXCH,
+    VKD3DSIH_IMM_ATOMIC_CONSUME,
+    VKD3DSIH_IMM_ATOMIC_EXCH,
+    VKD3DSIH_IMM_ATOMIC_IADD,
+    VKD3DSIH_IMM_ATOMIC_IMAX,
+    VKD3DSIH_IMM_ATOMIC_IMIN,
+    VKD3DSIH_IMM_ATOMIC_OR,
+    VKD3DSIH_IMM_ATOMIC_UMAX,
+    VKD3DSIH_IMM_ATOMIC_UMIN,
+    VKD3DSIH_IMM_ATOMIC_XOR,
+    VKD3DSIH_IMUL,
+    VKD3DSIH_INE,
+    VKD3DSIH_INEG,
+    VKD3DSIH_ISHL,
+    VKD3DSIH_ISHR,
+    VKD3DSIH_ITOF,
+    VKD3DSIH_LABEL,
+    VKD3DSIH_LD,
+    VKD3DSIH_LD2DMS,
+    VKD3DSIH_LD_RAW,
+    VKD3DSIH_LD_STRUCTURED,
+    VKD3DSIH_LD_UAV_TYPED,
+    VKD3DSIH_LIT,
+    VKD3DSIH_LOD,
+    VKD3DSIH_LOG,
+    VKD3DSIH_LOGP,
+    VKD3DSIH_LOOP,
+    VKD3DSIH_LRP,
+    VKD3DSIH_LT,
+    VKD3DSIH_M3x2,
+    VKD3DSIH_M3x3,
+    VKD3DSIH_M3x4,
+    VKD3DSIH_M4x3,
+    VKD3DSIH_M4x4,
+    VKD3DSIH_MAD,
+    VKD3DSIH_MAX,
+    VKD3DSIH_MIN,
+    VKD3DSIH_MOV,
+    VKD3DSIH_MOVA,
+    VKD3DSIH_MOVC,
+    VKD3DSIH_MUL,
+    VKD3DSIH_NE,
+    VKD3DSIH_NOP,
+    VKD3DSIH_NOT,
+    VKD3DSIH_NRM,
+    VKD3DSIH_OR,
+    VKD3DSIH_PHASE,
+    VKD3DSIH_POW,
+    VKD3DSIH_RCP,
+    VKD3DSIH_REP,
+    VKD3DSIH_RESINFO,
+    VKD3DSIH_RET,
+    VKD3DSIH_RETP,
+    VKD3DSIH_ROUND_NE,
+    VKD3DSIH_ROUND_NI,
+    VKD3DSIH_ROUND_PI,
+    VKD3DSIH_ROUND_Z,
+    VKD3DSIH_RSQ,
+    VKD3DSIH_SAMPLE,
+    VKD3DSIH_SAMPLE_B,
+    VKD3DSIH_SAMPLE_C,
+    VKD3DSIH_SAMPLE_C_LZ,
+    VKD3DSIH_SAMPLE_GRAD,
+    VKD3DSIH_SAMPLE_INFO,
+    VKD3DSIH_SAMPLE_LOD,
+    VKD3DSIH_SAMPLE_POS,
+    VKD3DSIH_SETP,
+    VKD3DSIH_SGE,
+    VKD3DSIH_SGN,
+    VKD3DSIH_SINCOS,
+    VKD3DSIH_SLT,
+    VKD3DSIH_SQRT,
+    VKD3DSIH_STORE_RAW,
+    VKD3DSIH_STORE_STRUCTURED,
+    VKD3DSIH_STORE_UAV_TYPED,
+    VKD3DSIH_SUB,
+    VKD3DSIH_SWAPC,
+    VKD3DSIH_SWITCH,
+    VKD3DSIH_SYNC,
+    VKD3DSIH_TEX,
+    VKD3DSIH_TEXBEM,
+    VKD3DSIH_TEXBEML,
+    VKD3DSIH_TEXCOORD,
+    VKD3DSIH_TEXDEPTH,
+    VKD3DSIH_TEXDP3,
+    VKD3DSIH_TEXDP3TEX,
+    VKD3DSIH_TEXKILL,
+    VKD3DSIH_TEXLDD,
+    VKD3DSIH_TEXLDL,
+    VKD3DSIH_TEXM3x2DEPTH,
+    VKD3DSIH_TEXM3x2PAD,
+    VKD3DSIH_TEXM3x2TEX,
+    VKD3DSIH_TEXM3x3,
+    VKD3DSIH_TEXM3x3DIFF,
+    VKD3DSIH_TEXM3x3PAD,
+    VKD3DSIH_TEXM3x3SPEC,
+    VKD3DSIH_TEXM3x3TEX,
+    VKD3DSIH_TEXM3x3VSPEC,
+    VKD3DSIH_TEXREG2AR,
+    VKD3DSIH_TEXREG2GB,
+    VKD3DSIH_TEXREG2RGB,
+    VKD3DSIH_UBFE,
+    VKD3DSIH_UDIV,
+    VKD3DSIH_UGE,
+    VKD3DSIH_ULT,
+    VKD3DSIH_UMAX,
+    VKD3DSIH_UMIN,
+    VKD3DSIH_UMUL,
+    VKD3DSIH_USHR,
+    VKD3DSIH_UTOF,
+    VKD3DSIH_XOR,
+
+    VKD3DSIH_INVALID,
+};
+
+enum vkd3d_shader_register_type
+{
+    VKD3DSPR_TEMP = 0,
+    VKD3DSPR_INPUT = 1,
+    VKD3DSPR_CONST = 2,
+    VKD3DSPR_ADDR = 3,
+    VKD3DSPR_TEXTURE = 3,
+    VKD3DSPR_RASTOUT = 4,
+    VKD3DSPR_ATTROUT = 5,
+    VKD3DSPR_TEXCRDOUT = 6,
+    VKD3DSPR_OUTPUT = 6,
+    VKD3DSPR_CONSTINT = 7,
+    VKD3DSPR_COLOROUT = 8,
+    VKD3DSPR_DEPTHOUT = 9,
+    VKD3DSPR_SAMPLER = 10,
+    VKD3DSPR_CONST2 = 11,
+    VKD3DSPR_CONST3 = 12,
+    VKD3DSPR_CONST4 = 13,
+    VKD3DSPR_CONSTBOOL = 14,
+    VKD3DSPR_LOOP = 15,
+    VKD3DSPR_TEMPFLOAT16 = 16,
+    VKD3DSPR_MISCTYPE = 17,
+    VKD3DSPR_LABEL = 18,
+    VKD3DSPR_PREDICATE = 19,
+    VKD3DSPR_IMMCONST,
+    VKD3DSPR_CONSTBUFFER,
+    VKD3DSPR_IMMCONSTBUFFER,
+    VKD3DSPR_PRIMID,
+    VKD3DSPR_NULL,
+    VKD3DSPR_RESOURCE,
+    VKD3DSPR_UAV,
+    VKD3DSPR_OUTPOINTID,
+    VKD3DSPR_FORKINSTID,
+    VKD3DSPR_JOININSTID,
+    VKD3DSPR_INCONTROLPOINT,
+    VKD3DSPR_OUTCONTROLPOINT,
+    VKD3DSPR_PATCHCONST,
+    VKD3DSPR_TESSCOORD,
+    VKD3DSPR_GROUPSHAREDMEM,
+    VKD3DSPR_THREADID,
+    VKD3DSPR_THREADGROUPID,
+    VKD3DSPR_LOCALTHREADID,
+    VKD3DSPR_LOCALTHREADINDEX,
+    VKD3DSPR_IDXTEMP,
+    VKD3DSPR_STREAM,
+    VKD3DSPR_FUNCTIONBODY,
+    VKD3DSPR_FUNCTIONPOINTER,
+    VKD3DSPR_COVERAGE,
+    VKD3DSPR_SAMPLEMASK,
+    VKD3DSPR_GSINSTID,
+    VKD3DSPR_DEPTHOUTGE,
+    VKD3DSPR_DEPTHOUTLE,
+    VKD3DSPR_RASTERIZER,
+
+    VKD3DSPR_INVALID = ~0u,
+};
+
+enum vkd3d_data_type
+{
+    VKD3D_DATA_FLOAT,
+    VKD3D_DATA_INT,
+    VKD3D_DATA_RESOURCE,
+    VKD3D_DATA_SAMPLER,
+    VKD3D_DATA_UAV,
+    VKD3D_DATA_UINT,
+    VKD3D_DATA_UNORM,
+    VKD3D_DATA_SNORM,
+    VKD3D_DATA_OPAQUE,
+};
+
+enum vkd3d_immconst_type
+{
+    VKD3D_IMMCONST_SCALAR,
+    VKD3D_IMMCONST_VEC4,
+};
+
+enum vkd3d_shader_src_modifier
+{
+    VKD3DSPSM_NONE = 0,
+    VKD3DSPSM_NEG = 1,
+    VKD3DSPSM_BIAS = 2,
+    VKD3DSPSM_BIASNEG = 3,
+    VKD3DSPSM_SIGN = 4,
+    VKD3DSPSM_SIGNNEG = 5,
+    VKD3DSPSM_COMP = 6,
+    VKD3DSPSM_X2 = 7,
+    VKD3DSPSM_X2NEG = 8,
+    VKD3DSPSM_DZ = 9,
+    VKD3DSPSM_DW = 10,
+    VKD3DSPSM_ABS = 11,
+    VKD3DSPSM_ABSNEG = 12,
+    VKD3DSPSM_NOT = 13,
+};
+
+#define VKD3DSP_WRITEMASK_0   0x1u /* .x r */
+#define VKD3DSP_WRITEMASK_1   0x2u /* .y g */
+#define VKD3DSP_WRITEMASK_2   0x4u /* .z b */
+#define VKD3DSP_WRITEMASK_3   0x8u /* .w a */
+#define VKD3DSP_WRITEMASK_ALL 0xfu /* all */
+
+enum vkd3d_shader_dst_modifier
+{
+    VKD3DSPDM_NONE = 0,
+    VKD3DSPDM_SATURATE = 1,
+    VKD3DSPDM_PARTIALPRECISION = 2,
+    VKD3DSPDM_MSAMPCENTROID = 4,
+};
+
+enum vkd3d_shader_interpolation_mode
+{
+    VKD3DSIM_NONE = 0,
+    VKD3DSIM_CONSTANT = 1,
+    VKD3DSIM_LINEAR = 2,
+    VKD3DSIM_LINEAR_CENTROID = 3,
+    VKD3DSIM_LINEAR_NOPERSPECTIVE = 4,
+    VKD3DSIM_LINEAR_NOPERSPECTIVE_CENTROID = 5,
+    VKD3DSIM_LINEAR_SAMPLE = 6,
+    VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE = 7,
+};
+
+enum vkd3d_shader_global_flags
+{
+    VKD3DSGF_REFACTORING_ALLOWED               = 0x01,
+    VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL         = 0x04,
+    VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS = 0x08,
+    VKD3DSGF_SKIP_OPTIMIZATION                 = 0x10,
+    VKD3DSGF_ENABLE_MINIMUM_PRECISION          = 0x20
+};
+
+enum vkd3d_shader_sync_flags
+{
+    VKD3DSSF_THREAD_GROUP        = 0x1,
+    VKD3DSSF_GROUP_SHARED_MEMORY = 0x2,
+};
+
+enum vkd3d_shader_uav_flags
+{
+    VKD3DSUF_GLOBALLY_COHERENT = 0x2,
+    VKD3DSUF_ORDER_PRESERVING_COUNTER = 0x100,
+};
+
+enum vkd3d_tessellator_domain
+{
+    VKD3D_TESSELLATOR_DOMAIN_LINE      = 1,
+    VKD3D_TESSELLATOR_DOMAIN_TRIANGLE  = 2,
+    VKD3D_TESSELLATOR_DOMAIN_QUAD      = 3,
+};
+
+#define VKD3DSI_NONE                    0x0
+#define VKD3DSI_TEXLD_PROJECT           0x1
+#define VKD3DSI_INDEXED_DYNAMIC         0x4
+#define VKD3DSI_RESINFO_RCP_FLOAT       0x1
+#define VKD3DSI_RESINFO_UINT            0x2
+#define VKD3DSI_SAMPLE_INFO_UINT        0x1
+#define VKD3DSI_SAMPLER_COMPARISON_MODE 0x1
+
+#define VKD3DSI_PRECISE_X         0x100
+#define VKD3DSI_PRECISE_Y         0x200
+#define VKD3DSI_PRECISE_Z         0x400
+#define VKD3DSI_PRECISE_W         0x800
+#define VKD3DSI_PRECISE_XYZW      (VKD3DSI_PRECISE_X | VKD3DSI_PRECISE_Y \
+                                  | VKD3DSI_PRECISE_Z | VKD3DSI_PRECISE_W)
+#define VKD3DSI_PRECISE_SHIFT     8
+
+enum vkd3d_shader_rel_op
+{
+    VKD3D_SHADER_REL_OP_GT = 1,
+    VKD3D_SHADER_REL_OP_EQ = 2,
+    VKD3D_SHADER_REL_OP_GE = 3,
+    VKD3D_SHADER_REL_OP_LT = 4,
+    VKD3D_SHADER_REL_OP_NE = 5,
+    VKD3D_SHADER_REL_OP_LE = 6,
+};
+
+enum vkd3d_shader_conditional_op
+{
+    VKD3D_SHADER_CONDITIONAL_OP_NZ = 0,
+    VKD3D_SHADER_CONDITIONAL_OP_Z  = 1
+};
+
+#define VKD3D_SM1_VS  0xfffeu
+#define VKD3D_SM1_PS  0xffffu
+#define VKD3D_SM4_PS  0x0000u
+#define VKD3D_SM4_VS  0x0001u
+#define VKD3D_SM4_GS  0x0002u
+#define VKD3D_SM5_HS  0x0003u
+#define VKD3D_SM5_DS  0x0004u
+#define VKD3D_SM5_CS  0x0005u
+
+/* Shader version tokens, and shader end tokens */
+#define VKD3DPS_VERSION(major, minor) ((VKD3D_SM1_PS << 16) | ((major) << 8) | (minor))
+#define VKD3DVS_VERSION(major, minor) ((VKD3D_SM1_VS << 16) | ((major) << 8) | (minor))
+
+#define MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE 4096
+#define MAX_REG_OUTPUT 32
+
+enum vkd3d_shader_type
+{
+    VKD3D_SHADER_TYPE_PIXEL,
+    VKD3D_SHADER_TYPE_VERTEX,
+    VKD3D_SHADER_TYPE_GEOMETRY,
+    VKD3D_SHADER_TYPE_HULL,
+    VKD3D_SHADER_TYPE_DOMAIN,
+    VKD3D_SHADER_TYPE_GRAPHICS_COUNT,
+
+    VKD3D_SHADER_TYPE_COMPUTE = VKD3D_SHADER_TYPE_GRAPHICS_COUNT,
+    VKD3D_SHADER_TYPE_COUNT,
+};
+
+struct vkd3d_shader_version
+{
+    enum vkd3d_shader_type type;
+    uint8_t major;
+    uint8_t minor;
+};
+
+struct vkd3d_shader_immediate_constant_buffer
+{
+    unsigned int vec4_count;
+    DWORD data[MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE];
+};
+
+struct vkd3d_shader_indexable_temp
+{
+    struct list entry;
+    unsigned int register_idx;
+    unsigned int register_size;
+    unsigned int component_count;
+};
+
+struct vkd3d_shader_register_index
+{
+    const struct vkd3d_shader_src_param *rel_addr;
+    unsigned int offset;
+};
+
+struct vkd3d_shader_register
+{
+    enum vkd3d_shader_register_type type;
+    enum vkd3d_data_type data_type;
+    struct vkd3d_shader_register_index idx[3];
+    enum vkd3d_immconst_type immconst_type;
+    union
+    {
+        DWORD immconst_uint[VKD3D_VEC4_SIZE];
+        float immconst_float[VKD3D_VEC4_SIZE];
+        unsigned fp_body_idx;
+    } u;
+};
+
+struct vkd3d_shader_dst_param
+{
+    struct vkd3d_shader_register reg;
+    DWORD write_mask;
+    DWORD modifiers;
+    DWORD shift;
+};
+
+struct vkd3d_shader_src_param
+{
+    struct vkd3d_shader_register reg;
+    DWORD swizzle;
+    enum vkd3d_shader_src_modifier modifiers;
+};
+
+struct vkd3d_shader_index_range
+{
+    struct vkd3d_shader_dst_param dst;
+    unsigned int register_count;
+};
+
+struct vkd3d_shader_resource
+{
+    struct vkd3d_shader_dst_param reg;
+    unsigned int register_space;
+    unsigned int register_index;
+};
+
+enum vkd3d_decl_usage
+{
+    VKD3D_DECL_USAGE_POSITION             = 0,
+    VKD3D_DECL_USAGE_BLEND_WEIGHT         = 1,
+    VKD3D_DECL_USAGE_BLEND_INDICES        = 2,
+    VKD3D_DECL_USAGE_NORMAL               = 3,
+    VKD3D_DECL_USAGE_PSIZE                = 4,
+    VKD3D_DECL_USAGE_TEXCOORD             = 5,
+    VKD3D_DECL_USAGE_TANGENT              = 6,
+    VKD3D_DECL_USAGE_BINORMAL             = 7,
+    VKD3D_DECL_USAGE_TESS_FACTOR          = 8,
+    VKD3D_DECL_USAGE_POSITIONT            = 9,
+    VKD3D_DECL_USAGE_COLOR                = 10,
+    VKD3D_DECL_USAGE_FOG                  = 11,
+    VKD3D_DECL_USAGE_DEPTH                = 12,
+    VKD3D_DECL_USAGE_SAMPLE               = 13
+};
+
+struct vkd3d_shader_semantic
+{
+    enum vkd3d_decl_usage usage;
+    unsigned int usage_idx;
+    enum vkd3d_shader_resource_type resource_type;
+    enum vkd3d_data_type resource_data_type;
+    struct vkd3d_shader_resource resource;
+};
+
+enum vkd3d_shader_input_sysval_semantic
+{
+    VKD3D_SIV_NONE                         = 0,
+    VKD3D_SIV_POSITION                     = 1,
+    VKD3D_SIV_CLIP_DISTANCE                = 2,
+    VKD3D_SIV_CULL_DISTANCE                = 3,
+    VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX    = 4,
+    VKD3D_SIV_VIEWPORT_ARRAY_INDEX         = 5,
+    VKD3D_SIV_VERTEX_ID                    = 6,
+    VKD3D_SIV_PRIMITIVE_ID                 = 7,
+    VKD3D_SIV_INSTANCE_ID                  = 8,
+    VKD3D_SIV_IS_FRONT_FACE                = 9,
+    VKD3D_SIV_SAMPLE_INDEX                 = 10,
+    VKD3D_SIV_QUAD_U0_TESS_FACTOR          = 11,
+    VKD3D_SIV_QUAD_V0_TESS_FACTOR          = 12,
+    VKD3D_SIV_QUAD_U1_TESS_FACTOR          = 13,
+    VKD3D_SIV_QUAD_V1_TESS_FACTOR          = 14,
+    VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR     = 15,
+    VKD3D_SIV_QUAD_V_INNER_TESS_FACTOR     = 16,
+    VKD3D_SIV_TRIANGLE_U_TESS_FACTOR       = 17,
+    VKD3D_SIV_TRIANGLE_V_TESS_FACTOR       = 18,
+    VKD3D_SIV_TRIANGLE_W_TESS_FACTOR       = 19,
+    VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR   = 20,
+    VKD3D_SIV_LINE_DETAIL_TESS_FACTOR      = 21,
+    VKD3D_SIV_LINE_DENSITY_TESS_FACTOR     = 22,
+};
+
+struct vkd3d_shader_desc
+{
+    const DWORD *byte_code;
+    size_t byte_code_size;
+    struct vkd3d_shader_signature input_signature;
+    struct vkd3d_shader_signature output_signature;
+    struct vkd3d_shader_signature patch_constant_signature;
+};
+
+struct vkd3d_shader_register_semantic
+{
+    struct vkd3d_shader_dst_param reg;
+    enum vkd3d_shader_input_sysval_semantic sysval_semantic;
+};
+
+struct vkd3d_shader_sampler
+{
+    struct vkd3d_shader_src_param src;
+    unsigned int register_space, register_index;
+};
+
+struct vkd3d_shader_constant_buffer
+{
+    struct vkd3d_shader_src_param src;
+    unsigned int size;
+    unsigned int register_space, register_index;
+};
+
+struct vkd3d_shader_structured_resource
+{
+    struct vkd3d_shader_resource resource;
+    unsigned int byte_stride;
+};
+
+struct vkd3d_shader_raw_resource
+{
+    struct vkd3d_shader_resource resource;
+};
+
+struct vkd3d_shader_tgsm
+{
+    unsigned int size;
+    unsigned int stride;
+};
+
+struct vkd3d_shader_tgsm_raw
+{
+    struct vkd3d_shader_dst_param reg;
+    unsigned int byte_count;
+};
+
+struct vkd3d_shader_tgsm_structured
+{
+    struct vkd3d_shader_dst_param reg;
+    unsigned int byte_stride;
+    unsigned int structure_count;
+};
+
+struct vkd3d_shader_thread_group_size
+{
+    unsigned int x, y, z;
+};
+
+struct vkd3d_shader_function_table_pointer
+{
+    unsigned int index;
+    unsigned int array_size;
+    unsigned int body_count;
+    unsigned int table_count;
+};
+
+struct vkd3d_shader_texel_offset
+{
+    signed char u, v, w;
+};
+
+enum vkd3d_primitive_type
+{
+    VKD3D_PT_UNDEFINED                    = 0,
+    VKD3D_PT_POINTLIST                    = 1,
+    VKD3D_PT_LINELIST                     = 2,
+    VKD3D_PT_LINESTRIP                    = 3,
+    VKD3D_PT_TRIANGLELIST                 = 4,
+    VKD3D_PT_TRIANGLESTRIP                = 5,
+    VKD3D_PT_TRIANGLEFAN                  = 6,
+    VKD3D_PT_LINELIST_ADJ                 = 10,
+    VKD3D_PT_LINESTRIP_ADJ                = 11,
+    VKD3D_PT_TRIANGLELIST_ADJ             = 12,
+    VKD3D_PT_TRIANGLESTRIP_ADJ            = 13,
+    VKD3D_PT_PATCH                        = 14,
+};
+
+struct vkd3d_shader_primitive_type
+{
+    enum vkd3d_primitive_type type;
+    unsigned int patch_vertex_count;
+};
+
+struct vkd3d_shader_instruction
+{
+    enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx;
+    DWORD flags;
+    unsigned int dst_count;
+    unsigned int src_count;
+    const struct vkd3d_shader_dst_param *dst;
+    const struct vkd3d_shader_src_param *src;
+    struct vkd3d_shader_texel_offset texel_offset;
+    enum vkd3d_shader_resource_type resource_type;
+    enum vkd3d_data_type resource_data_type;
+    bool coissue;
+    const struct vkd3d_shader_src_param *predicate;
+    union
+    {
+        struct vkd3d_shader_semantic semantic;
+        struct vkd3d_shader_register_semantic register_semantic;
+        struct vkd3d_shader_primitive_type primitive_type;
+        struct vkd3d_shader_dst_param dst;
+        struct vkd3d_shader_constant_buffer cb;
+        struct vkd3d_shader_sampler sampler;
+        unsigned int count;
+        unsigned int index;
+        const struct vkd3d_shader_immediate_constant_buffer *icb;
+        struct vkd3d_shader_raw_resource raw_resource;
+        struct vkd3d_shader_structured_resource structured_resource;
+        struct vkd3d_shader_tgsm_raw tgsm_raw;
+        struct vkd3d_shader_tgsm_structured tgsm_structured;
+        struct vkd3d_shader_thread_group_size thread_group_size;
+        enum vkd3d_tessellator_domain tessellator_domain;
+        enum vkd3d_shader_tessellator_output_primitive tessellator_output_primitive;
+        enum vkd3d_shader_tessellator_partitioning tessellator_partitioning;
+        float max_tessellation_factor;
+        struct vkd3d_shader_index_range index_range;
+        struct vkd3d_shader_indexable_temp indexable_temp;
+        struct vkd3d_shader_function_table_pointer fp;
+    } declaration;
+};
+
+static inline bool vkd3d_shader_instruction_has_texel_offset(const struct vkd3d_shader_instruction *ins)
+{
+    return ins->texel_offset.u || ins->texel_offset.v || ins->texel_offset.w;
+}
+
+static inline bool vkd3d_shader_register_is_input(const struct vkd3d_shader_register *reg)
+{
+    return reg->type == VKD3DSPR_INPUT || reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT;
+}
+
+static inline bool vkd3d_shader_register_is_output(const struct vkd3d_shader_register *reg)
+{
+    return reg->type == VKD3DSPR_OUTPUT || reg->type == VKD3DSPR_COLOROUT;
+}
+
+void vkd3d_shader_trace(void *data) DECLSPEC_HIDDEN;
+
+const char *shader_get_type_prefix(enum vkd3d_shader_type type) DECLSPEC_HIDDEN;
+
+void *shader_sm4_init(const DWORD *byte_code, size_t byte_code_size,
+        const struct vkd3d_shader_signature *output_signature) DECLSPEC_HIDDEN;
+void shader_sm4_free(void *data) DECLSPEC_HIDDEN;
+void shader_sm4_read_header(void *data, const DWORD **ptr,
+        struct vkd3d_shader_version *shader_version) DECLSPEC_HIDDEN;
+void shader_sm4_read_instruction(void *data, const DWORD **ptr,
+        struct vkd3d_shader_instruction *ins) DECLSPEC_HIDDEN;
+bool shader_sm4_is_end(void *data, const DWORD **ptr) DECLSPEC_HIDDEN;
+
+struct vkd3d_string_buffer
+{
+    char *buffer;
+    unsigned int buffer_size;
+    unsigned int content_size;
+};
+
+void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer) DECLSPEC_HIDDEN;
+bool vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer) DECLSPEC_HIDDEN;
+int vkd3d_string_buffer_vprintf(struct vkd3d_string_buffer *buffer, const char *format, va_list args) DECLSPEC_HIDDEN;
+
+struct vkd3d_shader_message_context
+{
+    enum vkd3d_shader_log_level log_level;
+    const char *source_name;
+    unsigned int line, column;
+    struct vkd3d_string_buffer messages;
+};
+
+void vkd3d_shader_message_context_cleanup(struct vkd3d_shader_message_context *context) DECLSPEC_HIDDEN;
+char *vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context) DECLSPEC_HIDDEN;
+bool vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context,
+        enum vkd3d_shader_log_level log_level, const char *source_name) DECLSPEC_HIDDEN;
+void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_message_context *context,
+        const char *function) DECLSPEC_HIDDEN;
+#define vkd3d_shader_message_context_trace_messages(context) \
+        vkd3d_shader_message_context_trace_messages_(context, __FUNCTION__)
+void vkd3d_shader_error(struct vkd3d_shader_message_context *context, enum vkd3d_shader_error error,
+        const char *format, ...) VKD3D_PRINTF_FUNC(3, 4) DECLSPEC_HIDDEN;
+void vkd3d_shader_verror(struct vkd3d_shader_message_context *context,
+        enum vkd3d_shader_error error, const char *format, va_list args) DECLSPEC_HIDDEN;
+
+int shader_extract_from_dxbc(const void *dxbc, size_t dxbc_length,
+        struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
+void free_shader_desc(struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
+
+int shader_parse_input_signature(const void *dxbc, size_t dxbc_length,
+        struct vkd3d_shader_message_context *message_context, 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,
+        const struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info,
+        const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info,
+        struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+int vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_instruction *instruction) DECLSPEC_HIDDEN;
+int vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *spirv) DECLSPEC_HIDDEN;
+void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler) DECLSPEC_HIDDEN;
+
+void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) DECLSPEC_HIDDEN;
+
+static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_type(
+        enum vkd3d_data_type data_type)
+{
+    switch (data_type)
+    {
+        case VKD3D_DATA_FLOAT:
+        case VKD3D_DATA_UNORM:
+        case VKD3D_DATA_SNORM:
+            return VKD3D_SHADER_COMPONENT_FLOAT;
+        case VKD3D_DATA_UINT:
+            return VKD3D_SHADER_COMPONENT_UINT;
+        case VKD3D_DATA_INT:
+            return VKD3D_SHADER_COMPONENT_INT;
+        default:
+            FIXME("Unhandled data type %#x.\n", data_type);
+            return VKD3D_SHADER_COMPONENT_UINT;
+    }
+}
+
+static inline enum vkd3d_data_type vkd3d_data_type_from_component_type(
+        enum vkd3d_shader_component_type component_type)
+{
+    switch (component_type)
+    {
+        case VKD3D_SHADER_COMPONENT_FLOAT:
+            return VKD3D_DATA_FLOAT;
+        case VKD3D_SHADER_COMPONENT_UINT:
+            return VKD3D_DATA_UINT;
+        case VKD3D_SHADER_COMPONENT_INT:
+            return VKD3D_DATA_INT;
+        default:
+            FIXME("Unhandled component type %#x.\n", component_type);
+            return VKD3D_DATA_FLOAT;
+    }
+}
+
+static inline unsigned int vkd3d_write_mask_get_component_idx(DWORD write_mask)
+{
+    unsigned int i;
+
+    assert(write_mask);
+    for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+            return i;
+    }
+
+    FIXME("Invalid write mask %#x.\n", write_mask);
+    return 0;
+}
+
+static inline unsigned int vkd3d_write_mask_component_count(DWORD write_mask)
+{
+    unsigned int count = vkd3d_popcount(write_mask & VKD3DSP_WRITEMASK_ALL);
+    assert(1 <= count && count <= VKD3D_VEC4_SIZE);
+    return count;
+}
+
+static inline unsigned int vkd3d_write_mask_from_component_count(unsigned int component_count)
+{
+    assert(component_count <= VKD3D_VEC4_SIZE);
+    return (VKD3DSP_WRITEMASK_0 << component_count) - 1;
+}
+
+static inline unsigned int vkd3d_swizzle_get_component(DWORD swizzle,
+        unsigned int idx)
+{
+    return (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(idx)) & VKD3D_SHADER_SWIZZLE_MASK;
+}
+
+static inline unsigned int vkd3d_compact_swizzle(unsigned int swizzle, unsigned int write_mask)
+{
+    unsigned int i, compacted_swizzle = 0;
+
+    for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+    {
+        if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
+        {
+            compacted_swizzle <<= VKD3D_SHADER_SWIZZLE_SHIFT(1);
+            compacted_swizzle |= vkd3d_swizzle_get_component(swizzle, i);
+        }
+    }
+
+    return compacted_swizzle;
+}
+
+struct vkd3d_struct
+{
+    enum vkd3d_shader_structure_type type;
+    const void *next;
+};
+
+#define vkd3d_find_struct(c, t) vkd3d_find_struct_(c, VKD3D_SHADER_STRUCTURE_TYPE_##t)
+static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain,
+        enum vkd3d_shader_structure_type type)
+{
+    while (chain)
+    {
+        if (chain->type == type)
+            return (void *)chain;
+
+        chain = chain->next;
+    }
+
+    return NULL;
+}
+
+#define VKD3D_DXBC_MAX_SOURCE_COUNT 6
+#define VKD3D_DXBC_HEADER_SIZE (8 * sizeof(uint32_t))
+
+#endif  /* __VKD3D_SHADER_PRIVATE_H */
diff --git a/dlls/vkd3d/libs/vkd3d-utils/libvkd3d-utils.pc.in b/dlls/vkd3d/libs/vkd3d-utils/libvkd3d-utils.pc.in
new file mode 100644
index 00000000000..31d2a89c3fc
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-utils/libvkd3d-utils.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: vkd3d-utils
+Description: The vkd3d 3D Graphics Utility Library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}/vkd3d
+Libs: -L${libdir} -lvkd3d-utils
diff --git a/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils.map b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils.map
new file mode 100644
index 00000000000..fb3912406cb
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils.map
@@ -0,0 +1,17 @@
+VKD3D_1_0
+{
+global:
+    D3D12CreateDevice;
+    D3D12CreateDeviceVKD3D;
+    D3D12CreateRootSignatureDeserializer;
+    D3D12CreateVersionedRootSignatureDeserializer;
+    D3D12GetDebugInterface;
+    D3D12SerializeRootSignature;
+    D3D12SerializeVersionedRootSignature;
+    vkd3d_create_event;
+    vkd3d_destroy_event;
+    vkd3d_signal_event;
+    vkd3d_wait_event;
+
+local: *;
+};
diff --git a/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c
new file mode 100644
index 00000000000..c19fe7f1fc5
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_utils_private.h"
+#undef D3D12CreateDevice
+
+VKD3D_DEBUG_ENV_NAME("VKD3D_DEBUG");
+
+HRESULT WINAPI D3D12GetDebugInterface(REFIID iid, void **debug)
+{
+    FIXME("iid %s, debug %p stub!\n", debugstr_guid(iid), debug);
+
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI D3D12CreateDeviceVKD3D(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_feature_level,
+        REFIID iid, void **device, enum vkd3d_api_version api_version)
+{
+    struct vkd3d_optional_instance_extensions_info optional_extensions_info;
+    struct vkd3d_instance_create_info instance_create_info;
+    struct vkd3d_device_create_info device_create_info;
+
+    static const char * const instance_extensions[] =
+    {
+        VK_KHR_SURFACE_EXTENSION_NAME,
+    };
+    static const char * const optional_instance_extensions[] =
+    {
+        "VK_KHR_xcb_surface",
+        "VK_MVK_macos_surface",
+    };
+    static const char * const device_extensions[] =
+    {
+        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+    };
+    struct vkd3d_application_info application_info =
+    {
+        .type = VKD3D_STRUCTURE_TYPE_APPLICATION_INFO,
+        .api_version = api_version,
+    };
+
+    TRACE("adapter %p, minimum_feature_level %#x, iid %s, device %p, api_version %#x.\n",
+            adapter, minimum_feature_level, debugstr_guid(iid), device, api_version);
+
+    if (adapter)
+        FIXME("Ignoring adapter %p.\n", adapter);
+
+    memset(&optional_extensions_info, 0, sizeof(optional_extensions_info));
+    optional_extensions_info.type = VKD3D_STRUCTURE_TYPE_OPTIONAL_INSTANCE_EXTENSIONS_INFO;
+    optional_extensions_info.next = &application_info;
+    optional_extensions_info.extensions = optional_instance_extensions;
+    optional_extensions_info.extension_count = ARRAY_SIZE(optional_instance_extensions);
+
+    memset(&instance_create_info, 0, sizeof(instance_create_info));
+    instance_create_info.type = VKD3D_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    instance_create_info.next = &optional_extensions_info;
+    instance_create_info.pfn_signal_event = vkd3d_signal_event;
+    instance_create_info.wchar_size = sizeof(WCHAR);
+    instance_create_info.instance_extensions = instance_extensions;
+    instance_create_info.instance_extension_count = ARRAY_SIZE(instance_extensions);
+
+    memset(&device_create_info, 0, sizeof(device_create_info));
+    device_create_info.type = VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+    device_create_info.next = NULL;
+    device_create_info.minimum_feature_level = minimum_feature_level;
+    device_create_info.instance_create_info = &instance_create_info;
+    device_create_info.device_extensions = device_extensions;
+    device_create_info.device_extension_count = ARRAY_SIZE(device_extensions);
+
+    return vkd3d_create_device(&device_create_info, iid, device);
+}
+
+HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter,
+        D3D_FEATURE_LEVEL minimum_feature_level, REFIID iid, void **device)
+{
+    return D3D12CreateDeviceVKD3D(adapter, minimum_feature_level, iid, device, VKD3D_API_VERSION_1_0);
+}
+
+HRESULT WINAPI D3D12CreateRootSignatureDeserializer(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer)
+{
+    TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
+            data, data_size, debugstr_guid(iid), deserializer);
+
+    return vkd3d_create_root_signature_deserializer(data, data_size, iid, deserializer);
+}
+
+HRESULT WINAPI D3D12CreateVersionedRootSignatureDeserializer(const void *data, SIZE_T data_size,
+        REFIID iid,void **deserializer)
+{
+    TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
+            data, data_size, debugstr_guid(iid), deserializer);
+
+    return vkd3d_create_versioned_root_signature_deserializer(data, data_size, iid, deserializer);
+}
+
+HRESULT WINAPI D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob)
+{
+    TRACE("desc %p, version %#x, blob %p, error_blob %p.\n", desc, version, blob, error_blob);
+
+    return vkd3d_serialize_root_signature(desc, version, blob, error_blob);
+}
+
+HRESULT WINAPI D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+        ID3DBlob **blob, ID3DBlob **error_blob)
+{
+    TRACE("desc %p, blob %p, error_blob %p.\n", desc, blob, error_blob);
+
+    return vkd3d_serialize_versioned_root_signature(desc, blob, error_blob);
+}
+
+/* Events */
+HANDLE vkd3d_create_event(void)
+{
+    struct vkd3d_event *event;
+    int rc;
+
+    TRACE(".\n");
+
+    if (!(event = vkd3d_malloc(sizeof(*event))))
+        return NULL;
+
+    if ((rc = pthread_mutex_init(&event->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        vkd3d_free(event);
+        return NULL;
+    }
+    if ((rc = pthread_cond_init(&event->cond, NULL)))
+    {
+        ERR("Failed to initialize condition variable, error %d.\n", rc);
+        pthread_mutex_destroy(&event->mutex);
+        vkd3d_free(event);
+        return NULL;
+    }
+
+    event->is_signaled = false;
+
+    TRACE("Created event %p.\n", event);
+
+    return event;
+}
+
+unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds)
+{
+    struct vkd3d_event *impl = event;
+    int rc;
+
+    TRACE("event %p, milliseconds %u.\n", event, milliseconds);
+
+    if ((rc = pthread_mutex_lock(&impl->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return VKD3D_WAIT_FAILED;
+    }
+
+    if (impl->is_signaled || !milliseconds)
+    {
+        bool is_signaled = impl->is_signaled;
+        impl->is_signaled = false;
+        pthread_mutex_unlock(&impl->mutex);
+        return is_signaled ? VKD3D_WAIT_OBJECT_0 : VKD3D_WAIT_TIMEOUT;
+    }
+
+    if (milliseconds == VKD3D_INFINITE)
+    {
+        do
+        {
+            if ((rc = pthread_cond_wait(&impl->cond, &impl->mutex)))
+            {
+                ERR("Failed to wait on condition variable, error %d.\n", rc);
+                pthread_mutex_unlock(&impl->mutex);
+                return VKD3D_WAIT_FAILED;
+            }
+        } while (!impl->is_signaled);
+
+        impl->is_signaled = false;
+        pthread_mutex_unlock(&impl->mutex);
+        return VKD3D_WAIT_OBJECT_0;
+    }
+
+    pthread_mutex_unlock(&impl->mutex);
+    FIXME("Timed wait not implemented yet.\n");
+    return VKD3D_WAIT_FAILED;
+}
+
+HRESULT vkd3d_signal_event(HANDLE event)
+{
+    struct vkd3d_event *impl = event;
+    int rc;
+
+    TRACE("event %p.\n", event);
+
+    if ((rc = pthread_mutex_lock(&impl->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return E_FAIL;
+    }
+    impl->is_signaled = true;
+    pthread_cond_signal(&impl->cond);
+    pthread_mutex_unlock(&impl->mutex);
+
+    return S_OK;
+}
+
+void vkd3d_destroy_event(HANDLE event)
+{
+    struct vkd3d_event *impl = event;
+    int rc;
+
+    TRACE("event %p.\n", event);
+
+    if ((rc = pthread_mutex_destroy(&impl->mutex)))
+        ERR("Failed to destroy mutex, error %d.\n", rc);
+    if ((rc = pthread_cond_destroy(&impl->cond)))
+        ERR("Failed to destroy condition variable, error %d.\n", rc);
+    vkd3d_free(impl);
+}
diff --git a/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h
new file mode 100644
index 00000000000..6b5851e6bfc
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_UTILS_PRIVATE_H
+#define __VKD3D_UTILS_PRIVATE_H
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define VK_NO_PROTOTYPES
+
+#include <pthread.h>
+#include <vkd3d.h>
+
+#include "vkd3d_memory.h"
+#include <vkd3d_utils.h>
+
+struct vkd3d_event
+{
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    BOOL is_signaled;
+};
+
+#endif  /* __VKD3D_UTILS_PRIVATE_H */
diff --git a/dlls/vkd3d/libs/vkd3d/command.c b/dlls/vkd3d/libs/vkd3d/command.c
new file mode 100644
index 00000000000..e5c6791b83a
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/command.c
@@ -0,0 +1,6461 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_private.h"
+
+static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence);
+
+HRESULT vkd3d_queue_create(struct d3d12_device *device,
+        uint32_t family_index, const VkQueueFamilyProperties *properties, struct vkd3d_queue **queue)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_queue *object;
+    int rc;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if ((rc = pthread_mutex_init(&object->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        vkd3d_free(object);
+        return hresult_from_errno(rc);
+    }
+
+    object->completed_sequence_number = 0;
+    object->submitted_sequence_number = 0;
+
+    object->vk_family_index = family_index;
+    object->vk_queue_flags = properties->queueFlags;
+    object->timestamp_bits = properties->timestampValidBits;
+
+    object->semaphores = NULL;
+    object->semaphores_size = 0;
+    object->semaphore_count = 0;
+
+    memset(object->old_vk_semaphores, 0, sizeof(object->old_vk_semaphores));
+
+    VK_CALL(vkGetDeviceQueue(device->vk_device, family_index, 0, &object->vk_queue));
+
+    TRACE("Created queue %p for queue family index %u.\n", object, family_index);
+
+    *queue = object;
+
+    return S_OK;
+}
+
+void vkd3d_queue_destroy(struct vkd3d_queue *queue, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int i;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&queue->mutex)))
+        ERR("Failed to lock mutex, error %d.\n", rc);
+
+    for (i = 0; i < queue->semaphore_count; ++i)
+        VK_CALL(vkDestroySemaphore(device->vk_device, queue->semaphores[i].vk_semaphore, NULL));
+
+    vkd3d_free(queue->semaphores);
+
+    for (i = 0; i < ARRAY_SIZE(queue->old_vk_semaphores); ++i)
+    {
+        if (queue->old_vk_semaphores[i])
+            VK_CALL(vkDestroySemaphore(device->vk_device, queue->old_vk_semaphores[i], NULL));
+    }
+
+    if (!rc)
+        pthread_mutex_unlock(&queue->mutex);
+
+    pthread_mutex_destroy(&queue->mutex);
+    vkd3d_free(queue);
+}
+
+VkQueue vkd3d_queue_acquire(struct vkd3d_queue *queue)
+{
+    int rc;
+
+    TRACE("queue %p.\n", queue);
+
+    if ((rc = pthread_mutex_lock(&queue->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return VK_NULL_HANDLE;
+    }
+
+    assert(queue->vk_queue);
+    return queue->vk_queue;
+}
+
+void vkd3d_queue_release(struct vkd3d_queue *queue)
+{
+    TRACE("queue %p.\n", queue);
+
+    pthread_mutex_unlock(&queue->mutex);
+}
+
+static VkResult vkd3d_queue_wait_idle(struct vkd3d_queue *queue,
+        const struct vkd3d_vk_device_procs *vk_procs)
+{
+    VkQueue vk_queue;
+    VkResult vr;
+
+    if ((vk_queue = vkd3d_queue_acquire(queue)))
+    {
+        vr = VK_CALL(vkQueueWaitIdle(vk_queue));
+        vkd3d_queue_release(queue);
+
+        if (vr < 0)
+            WARN("Failed to wait for queue, vr %d.\n", vr);
+    }
+    else
+    {
+        ERR("Failed to acquire queue %p.\n", queue);
+        vr = VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+
+    return vr;
+}
+
+static void vkd3d_queue_update_sequence_number(struct vkd3d_queue *queue,
+        uint64_t sequence_number, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int destroyed_semaphore_count = 0;
+    uint64_t completed_sequence_number;
+    VkSemaphore vk_semaphore;
+    unsigned int i, j;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&queue->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    completed_sequence_number = queue->completed_sequence_number;
+    queue->completed_sequence_number = max(sequence_number, queue->completed_sequence_number);
+
+    TRACE("Queue %p sequence number %"PRIu64" -> %"PRIu64".\n",
+            queue, completed_sequence_number, queue->completed_sequence_number);
+
+    for (i = 0; i < queue->semaphore_count; ++i)
+    {
+        if (queue->semaphores[i].sequence_number > queue->completed_sequence_number)
+            break;
+
+        vk_semaphore = queue->semaphores[i].vk_semaphore;
+
+        /* Try to store the Vulkan semaphore for reuse. */
+        for (j = 0; j < ARRAY_SIZE(queue->old_vk_semaphores); ++j)
+        {
+            if (queue->old_vk_semaphores[j] == VK_NULL_HANDLE)
+            {
+                queue->old_vk_semaphores[j] = vk_semaphore;
+                vk_semaphore = VK_NULL_HANDLE;
+                break;
+            }
+        }
+
+        if (!vk_semaphore)
+            continue;
+
+        VK_CALL(vkDestroySemaphore(device->vk_device, vk_semaphore, NULL));
+        ++destroyed_semaphore_count;
+    }
+    if (i > 0)
+    {
+        queue->semaphore_count -= i;
+        memmove(queue->semaphores, &queue->semaphores[i], queue->semaphore_count * sizeof(*queue->semaphores));
+    }
+
+    if (destroyed_semaphore_count)
+        TRACE("Destroyed %u Vulkan semaphores.\n", destroyed_semaphore_count);
+
+    pthread_mutex_unlock(&queue->mutex);
+}
+
+static uint64_t vkd3d_queue_reset_sequence_number_locked(struct vkd3d_queue *queue)
+{
+    unsigned int i;
+
+    WARN("Ressetting sequence number for queue %p.\n", queue);
+
+    queue->completed_sequence_number = 0;
+    queue->submitted_sequence_number = 1;
+
+    for (i = 0; i < queue->semaphore_count; ++i)
+        queue->semaphores[i].sequence_number = queue->submitted_sequence_number;
+
+    return queue->submitted_sequence_number;
+}
+
+static VkResult vkd3d_queue_create_vk_semaphore_locked(struct vkd3d_queue *queue,
+        struct d3d12_device *device, VkSemaphore *vk_semaphore)
+{
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkSemaphoreCreateInfo semaphore_info;
+    unsigned int i;
+    VkResult vr;
+
+    *vk_semaphore = VK_NULL_HANDLE;
+
+    for (i = 0; i < ARRAY_SIZE(queue->old_vk_semaphores); ++i)
+    {
+        if ((*vk_semaphore = queue->old_vk_semaphores[i]))
+        {
+            queue->old_vk_semaphores[i] = VK_NULL_HANDLE;
+            break;
+        }
+    }
+
+    if (*vk_semaphore)
+        return VK_SUCCESS;
+
+    vk_procs = &device->vk_procs;
+
+    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphore_info.pNext = NULL;
+    semaphore_info.flags = 0;
+    if ((vr = VK_CALL(vkCreateSemaphore(device->vk_device, &semaphore_info, NULL, vk_semaphore))) < 0)
+    {
+        WARN("Failed to create Vulkan semaphore, vr %d.\n", vr);
+        *vk_semaphore = VK_NULL_HANDLE;
+    }
+
+    return vr;
+}
+
+/* Fence worker thread */
+static HRESULT vkd3d_enqueue_gpu_fence(struct vkd3d_fence_worker *worker,
+        VkFence vk_fence, struct d3d12_fence *fence, uint64_t value,
+        struct vkd3d_queue *queue, uint64_t queue_sequence_number)
+{
+    struct vkd3d_waiting_fence *waiting_fence;
+    int rc;
+
+    TRACE("worker %p, fence %p, value %#"PRIx64".\n", worker, fence, value);
+
+    if ((rc = pthread_mutex_lock(&worker->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if (!vkd3d_array_reserve((void **)&worker->enqueued_fences, &worker->enqueued_fences_size,
+            worker->enqueued_fence_count + 1, sizeof(*worker->enqueued_fences)))
+    {
+        ERR("Failed to add GPU fence.\n");
+        pthread_mutex_unlock(&worker->mutex);
+        return E_OUTOFMEMORY;
+    }
+
+    worker->enqueued_fences[worker->enqueued_fence_count].vk_fence = vk_fence;
+    waiting_fence = &worker->enqueued_fences[worker->enqueued_fence_count].waiting_fence;
+    waiting_fence->fence = fence;
+    waiting_fence->value = value;
+    waiting_fence->queue = queue;
+    waiting_fence->queue_sequence_number = queue_sequence_number;
+    ++worker->enqueued_fence_count;
+
+    InterlockedIncrement(&fence->pending_worker_operation_count);
+
+    pthread_cond_signal(&worker->cond);
+    pthread_mutex_unlock(&worker->mutex);
+
+    return S_OK;
+}
+
+static void vkd3d_fence_worker_remove_fence(struct vkd3d_fence_worker *worker, struct d3d12_fence *fence)
+{
+    LONG count;
+    int rc;
+
+    if (!(count = atomic_add_fetch(&fence->pending_worker_operation_count, 0)))
+        return;
+
+    WARN("Waiting for %u pending fence operations (fence %p).\n", count, fence);
+
+    if ((rc = pthread_mutex_lock(&worker->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    while ((count = atomic_add_fetch(&fence->pending_worker_operation_count, 0)))
+    {
+        TRACE("Still waiting for %u pending fence operations (fence %p).\n", count, fence);
+
+        worker->pending_fence_destruction = true;
+        pthread_cond_signal(&worker->cond);
+
+        pthread_cond_wait(&worker->fence_destruction_cond, &worker->mutex);
+    }
+
+    TRACE("Removed fence %p.\n", fence);
+
+    pthread_mutex_unlock(&worker->mutex);
+}
+
+static void vkd3d_fence_worker_move_enqueued_fences_locked(struct vkd3d_fence_worker *worker)
+{
+    unsigned int i;
+    size_t count;
+    bool ret;
+
+    if (!worker->enqueued_fence_count)
+        return;
+
+    count = worker->fence_count + worker->enqueued_fence_count;
+
+    ret = vkd3d_array_reserve((void **)&worker->vk_fences, &worker->vk_fences_size,
+            count, sizeof(*worker->vk_fences));
+    ret &= vkd3d_array_reserve((void **)&worker->fences, &worker->fences_size,
+            count, sizeof(*worker->fences));
+    if (!ret)
+    {
+        ERR("Failed to reserve memory.\n");
+        return;
+    }
+
+    for (i = 0; i < worker->enqueued_fence_count; ++i)
+    {
+        struct vkd3d_enqueued_fence *current = &worker->enqueued_fences[i];
+
+        worker->vk_fences[worker->fence_count] = current->vk_fence;
+        worker->fences[worker->fence_count] = current->waiting_fence;
+        ++worker->fence_count;
+    }
+    assert(worker->fence_count == count);
+    worker->enqueued_fence_count = 0;
+}
+
+static void vkd3d_wait_for_gpu_fences(struct vkd3d_fence_worker *worker)
+{
+    struct d3d12_device *device = worker->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int i, j;
+    VkFence vk_fence;
+    HRESULT hr;
+    int vr;
+
+    if (!worker->fence_count)
+        return;
+
+    vr = VK_CALL(vkWaitForFences(device->vk_device,
+            worker->fence_count, worker->vk_fences, VK_FALSE, ~(uint64_t)0));
+    if (vr == VK_TIMEOUT)
+        return;
+    if (vr != VK_SUCCESS)
+    {
+        ERR("Failed to wait for Vulkan fences, vr %d.\n", vr);
+        return;
+    }
+
+    for (i = 0, j = 0; i < worker->fence_count; ++i)
+    {
+        vk_fence = worker->vk_fences[i];
+        if (!(vr = VK_CALL(vkGetFenceStatus(device->vk_device, vk_fence))))
+        {
+            struct vkd3d_waiting_fence *current = &worker->fences[i];
+
+            TRACE("Signaling fence %p value %#"PRIx64".\n", current->fence, current->value);
+            if (FAILED(hr = d3d12_fence_signal(current->fence, current->value, vk_fence)))
+                ERR("Failed to signal D3D12 fence, hr %#x.\n", hr);
+
+            InterlockedDecrement(&current->fence->pending_worker_operation_count);
+
+            vkd3d_queue_update_sequence_number(current->queue, current->queue_sequence_number, device);
+            continue;
+        }
+
+        if (vr != VK_NOT_READY)
+            ERR("Failed to get Vulkan fence status, vr %d.\n", vr);
+
+        if (i != j)
+        {
+            worker->vk_fences[j] = worker->vk_fences[i];
+            worker->fences[j] = worker->fences[i];
+        }
+        ++j;
+    }
+    worker->fence_count = j;
+}
+
+static void *vkd3d_fence_worker_main(void *arg)
+{
+    struct vkd3d_fence_worker *worker = arg;
+    int rc;
+
+    vkd3d_set_thread_name("vkd3d_fence");
+
+    for (;;)
+    {
+        vkd3d_wait_for_gpu_fences(worker);
+
+        if (!worker->fence_count || atomic_add_fetch(&worker->enqueued_fence_count, 0))
+        {
+            if ((rc = pthread_mutex_lock(&worker->mutex)))
+            {
+                ERR("Failed to lock mutex, error %d.\n", rc);
+                break;
+            }
+
+            if (worker->pending_fence_destruction)
+            {
+                pthread_cond_broadcast(&worker->fence_destruction_cond);
+                worker->pending_fence_destruction = false;
+            }
+
+            if (worker->enqueued_fence_count)
+            {
+                vkd3d_fence_worker_move_enqueued_fences_locked(worker);
+            }
+            else
+            {
+                if (worker->should_exit)
+                {
+                    pthread_mutex_unlock(&worker->mutex);
+                    break;
+                }
+
+                if ((rc = pthread_cond_wait(&worker->cond, &worker->mutex)))
+                {
+                    ERR("Failed to wait on condition variable, error %d.\n", rc);
+                    pthread_mutex_unlock(&worker->mutex);
+                    break;
+                }
+            }
+
+            pthread_mutex_unlock(&worker->mutex);
+        }
+    }
+
+    return NULL;
+}
+
+HRESULT vkd3d_fence_worker_start(struct vkd3d_fence_worker *worker,
+        struct d3d12_device *device)
+{
+    HRESULT hr;
+    int rc;
+
+    TRACE("worker %p.\n", worker);
+
+    worker->should_exit = false;
+    worker->pending_fence_destruction = false;
+    worker->device = device;
+
+    worker->enqueued_fence_count = 0;
+    worker->enqueued_fences = NULL;
+    worker->enqueued_fences_size = 0;
+
+    worker->fence_count = 0;
+
+    worker->vk_fences = NULL;
+    worker->vk_fences_size = 0;
+    worker->fences = NULL;
+    worker->fences_size = 0;
+
+    if ((rc = pthread_mutex_init(&worker->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if ((rc = pthread_cond_init(&worker->cond, NULL)))
+    {
+        ERR("Failed to initialize condition variable, error %d.\n", rc);
+        pthread_mutex_destroy(&worker->mutex);
+        return hresult_from_errno(rc);
+    }
+
+    if ((rc = pthread_cond_init(&worker->fence_destruction_cond, NULL)))
+    {
+        ERR("Failed to initialize condition variable, error %d.\n", rc);
+        pthread_mutex_destroy(&worker->mutex);
+        pthread_cond_destroy(&worker->cond);
+        return hresult_from_errno(rc);
+    }
+
+    if (FAILED(hr = vkd3d_create_thread(device->vkd3d_instance,
+            vkd3d_fence_worker_main, worker, &worker->thread)))
+    {
+        pthread_mutex_destroy(&worker->mutex);
+        pthread_cond_destroy(&worker->cond);
+        pthread_cond_destroy(&worker->fence_destruction_cond);
+    }
+
+    return hr;
+}
+
+HRESULT vkd3d_fence_worker_stop(struct vkd3d_fence_worker *worker,
+        struct d3d12_device *device)
+{
+    HRESULT hr;
+    int rc;
+
+    TRACE("worker %p.\n", worker);
+
+    if ((rc = pthread_mutex_lock(&worker->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    worker->should_exit = true;
+    pthread_cond_signal(&worker->cond);
+
+    pthread_mutex_unlock(&worker->mutex);
+
+    if (FAILED(hr = vkd3d_join_thread(device->vkd3d_instance, &worker->thread)))
+        return hr;
+
+    pthread_mutex_destroy(&worker->mutex);
+    pthread_cond_destroy(&worker->cond);
+    pthread_cond_destroy(&worker->fence_destruction_cond);
+
+    vkd3d_free(worker->enqueued_fences);
+    vkd3d_free(worker->vk_fences);
+    vkd3d_free(worker->fences);
+
+    return S_OK;
+}
+
+static const struct d3d12_root_parameter *root_signature_get_parameter(
+        const struct d3d12_root_signature *root_signature, unsigned int index)
+{
+    assert(index < root_signature->parameter_count);
+    return &root_signature->parameters[index];
+}
+
+static const struct d3d12_root_descriptor_table *root_signature_get_descriptor_table(
+        const struct d3d12_root_signature *root_signature, unsigned int index)
+{
+    const struct d3d12_root_parameter *p = root_signature_get_parameter(root_signature, index);
+    assert(p->parameter_type == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE);
+    return &p->u.descriptor_table;
+}
+
+static const struct d3d12_root_constant *root_signature_get_32bit_constants(
+        const struct d3d12_root_signature *root_signature, unsigned int index)
+{
+    const struct d3d12_root_parameter *p = root_signature_get_parameter(root_signature, index);
+    assert(p->parameter_type == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS);
+    return &p->u.constant;
+}
+
+static const struct d3d12_root_parameter *root_signature_get_root_descriptor(
+        const struct d3d12_root_signature *root_signature, unsigned int index)
+{
+    const struct d3d12_root_parameter *p = root_signature_get_parameter(root_signature, index);
+    assert(p->parameter_type == D3D12_ROOT_PARAMETER_TYPE_CBV
+        || p->parameter_type == D3D12_ROOT_PARAMETER_TYPE_SRV
+        || p->parameter_type == D3D12_ROOT_PARAMETER_TYPE_UAV);
+    return p;
+}
+
+/* ID3D12Fence */
+static struct d3d12_fence *impl_from_ID3D12Fence(ID3D12Fence *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_fence, ID3D12Fence_iface);
+}
+
+static VkResult d3d12_fence_create_vk_fence(struct d3d12_fence *fence, VkFence *vk_fence)
+{
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_device *device = fence->device;
+    VkFenceCreateInfo fence_info;
+    unsigned int i;
+    VkResult vr;
+    int rc;
+
+    *vk_fence = VK_NULL_HANDLE;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        goto create_fence;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(fence->old_vk_fences); ++i)
+    {
+        if ((*vk_fence = fence->old_vk_fences[i]))
+        {
+            fence->old_vk_fences[i] = VK_NULL_HANDLE;
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(&fence->mutex);
+
+    if (*vk_fence)
+        return VK_SUCCESS;
+
+create_fence:
+    vk_procs = &device->vk_procs;
+
+    fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fence_info.pNext = NULL;
+    fence_info.flags = 0;
+    if ((vr = VK_CALL(vkCreateFence(device->vk_device, &fence_info, NULL, vk_fence))) < 0)
+    {
+        WARN("Failed to create Vulkan fence, vr %d.\n", vr);
+        *vk_fence = VK_NULL_HANDLE;
+    }
+
+    return vr;
+}
+
+static void d3d12_fence_garbage_collect_vk_semaphores_locked(struct d3d12_fence *fence,
+        bool destroy_all)
+{
+    struct d3d12_device *device = fence->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_signaled_semaphore *current, *p;
+    unsigned int semaphore_count;
+
+    semaphore_count = fence->semaphore_count;
+    if (!destroy_all && semaphore_count < VKD3D_MAX_VK_SYNC_OBJECTS)
+        return;
+
+    LIST_FOR_EACH_ENTRY_SAFE(current, p, &fence->semaphores, struct vkd3d_signaled_semaphore, entry)
+    {
+        if (!destroy_all && fence->semaphore_count < VKD3D_MAX_VK_SYNC_OBJECTS)
+            break;
+
+        /* The semaphore doesn't have a pending signal operation if the fence
+         * was signaled. */
+        if ((current->vk_fence || current->is_acquired) && !destroy_all)
+            continue;
+
+        if (current->vk_fence)
+            WARN("Destroying potentially pending semaphore.\n");
+        assert(!current->is_acquired);
+
+        VK_CALL(vkDestroySemaphore(device->vk_device, current->vk_semaphore, NULL));
+        list_remove(&current->entry);
+        vkd3d_free(current);
+
+        --fence->semaphore_count;
+    }
+
+    if (semaphore_count != fence->semaphore_count)
+        TRACE("Destroyed %u Vulkan semaphores.\n", semaphore_count - fence->semaphore_count);
+}
+
+static void d3d12_fence_destroy_vk_objects(struct d3d12_fence *fence)
+{
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_device *device = fence->device;
+    unsigned int i;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    vk_procs = &device->vk_procs;
+
+    for (i = 0; i < ARRAY_SIZE(fence->old_vk_fences); ++i)
+    {
+        if (fence->old_vk_fences[i])
+            VK_CALL(vkDestroyFence(device->vk_device, fence->old_vk_fences[i], NULL));
+        fence->old_vk_fences[i] = VK_NULL_HANDLE;
+    }
+
+    d3d12_fence_garbage_collect_vk_semaphores_locked(fence, true);
+
+    pthread_mutex_unlock(&fence->mutex);
+}
+
+static struct vkd3d_signaled_semaphore *d3d12_fence_acquire_vk_semaphore(struct d3d12_fence *fence,
+        uint64_t value, uint64_t *completed_value)
+{
+    struct vkd3d_signaled_semaphore *semaphore;
+    struct vkd3d_signaled_semaphore *current;
+    uint64_t semaphore_value;
+    int rc;
+
+    TRACE("fence %p, value %#"PRIx64".\n", fence, value);
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return VK_NULL_HANDLE;
+    }
+
+    semaphore = NULL;
+    semaphore_value = ~(uint64_t)0;
+
+    LIST_FOR_EACH_ENTRY(current, &fence->semaphores, struct vkd3d_signaled_semaphore, entry)
+    {
+        /* Prefer a semaphore with the smallest value. */
+        if (!current->is_acquired && current->value >= value && semaphore_value >= current->value)
+        {
+            semaphore = current;
+            semaphore_value = current->value;
+        }
+        if (semaphore_value == value)
+            break;
+    }
+
+    if (semaphore)
+        semaphore->is_acquired = true;
+
+    *completed_value = fence->value;
+
+    pthread_mutex_unlock(&fence->mutex);
+
+    return semaphore;
+}
+
+static void d3d12_fence_remove_vk_semaphore(struct d3d12_fence *fence, struct vkd3d_signaled_semaphore *semaphore)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    assert(semaphore->is_acquired);
+
+    list_remove(&semaphore->entry);
+    vkd3d_free(semaphore);
+
+    --fence->semaphore_count;
+
+    pthread_mutex_unlock(&fence->mutex);
+}
+
+static void d3d12_fence_release_vk_semaphore(struct d3d12_fence *fence, struct vkd3d_signaled_semaphore *semaphore)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    assert(semaphore->is_acquired);
+    semaphore->is_acquired = false;
+
+    pthread_mutex_unlock(&fence->mutex);
+}
+
+static HRESULT d3d12_fence_add_vk_semaphore(struct d3d12_fence *fence,
+        VkSemaphore vk_semaphore, VkFence vk_fence, uint64_t value)
+{
+    struct vkd3d_signaled_semaphore *semaphore;
+    HRESULT hr = S_OK;
+    int rc;
+
+    TRACE("fence %p, value %#"PRIx64".\n", fence, value);
+
+    if (!(semaphore = vkd3d_malloc(sizeof(*semaphore))))
+    {
+        ERR("Failed to add semaphore.\n");
+        return E_OUTOFMEMORY;
+    }
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        vkd3d_free(semaphore);
+        return E_FAIL;
+    }
+
+    d3d12_fence_garbage_collect_vk_semaphores_locked(fence, false);
+
+    semaphore->value = value;
+    semaphore->vk_semaphore = vk_semaphore;
+    semaphore->vk_fence = vk_fence;
+    semaphore->is_acquired = false;
+
+    list_add_tail(&fence->semaphores, &semaphore->entry);
+    ++fence->semaphore_count;
+
+    pthread_mutex_unlock(&fence->mutex);
+
+    return hr;
+}
+
+static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence)
+{
+    struct d3d12_device *device = fence->device;
+    struct vkd3d_signaled_semaphore *current;
+    unsigned int i, j;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    fence->value = value;
+
+    for (i = 0, j = 0; i < fence->event_count; ++i)
+    {
+        struct vkd3d_waiting_event *current = &fence->events[i];
+
+        if (current->value <= value)
+        {
+            fence->device->signal_event(current->event);
+        }
+        else
+        {
+            if (i != j)
+                fence->events[j] = *current;
+            ++j;
+        }
+    }
+    fence->event_count = j;
+
+    if (vk_fence)
+    {
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        LIST_FOR_EACH_ENTRY(current, &fence->semaphores, struct vkd3d_signaled_semaphore, entry)
+        {
+            if (current->vk_fence == vk_fence)
+                current->vk_fence = VK_NULL_HANDLE;
+        }
+
+        for (i = 0; i < ARRAY_SIZE(fence->old_vk_fences); ++i)
+        {
+            if (fence->old_vk_fences[i] == VK_NULL_HANDLE)
+            {
+                fence->old_vk_fences[i] = vk_fence;
+                VK_CALL(vkResetFences(device->vk_device, 1, &vk_fence));
+                vk_fence = VK_NULL_HANDLE;
+                break;
+            }
+        }
+        if (vk_fence)
+            VK_CALL(vkDestroyFence(device->vk_device, vk_fence, NULL));
+    }
+
+    pthread_mutex_unlock(&fence->mutex);
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_QueryInterface(ID3D12Fence *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12Fence)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12Fence_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_fence_AddRef(ID3D12Fence *iface)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+    ULONG refcount = InterlockedIncrement(&fence->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", fence, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence *iface)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+    ULONG refcount = InterlockedDecrement(&fence->refcount);
+    int rc;
+
+    TRACE("%p decreasing refcount to %u.\n", fence, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = fence->device;
+
+        vkd3d_private_store_destroy(&fence->private_store);
+
+        vkd3d_fence_worker_remove_fence(&device->fence_worker, fence);
+
+        d3d12_fence_destroy_vk_objects(fence);
+
+        vkd3d_free(fence->events);
+        if ((rc = pthread_mutex_destroy(&fence->mutex)))
+            ERR("Failed to destroy mutex, error %d.\n", rc);
+        vkd3d_free(fence);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_GetPrivateData(ID3D12Fence *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n",
+            iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&fence->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateData(ID3D12Fence *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n",
+            iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&fence->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateDataInterface(ID3D12Fence *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&fence->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_SetName(ID3D12Fence *iface, const WCHAR *name)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, fence->device->wchar_size));
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_GetDevice(ID3D12Fence *iface, REFIID iid, void **device)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(fence->device, iid, device);
+}
+
+static UINT64 STDMETHODCALLTYPE d3d12_fence_GetCompletedValue(ID3D12Fence *iface)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+    uint64_t completed_value;
+    int rc;
+
+    TRACE("iface %p.\n", iface);
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return 0;
+    }
+    completed_value = fence->value;
+    pthread_mutex_unlock(&fence->mutex);
+    return completed_value;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *iface,
+        UINT64 value, HANDLE event)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+    unsigned int i;
+    int rc;
+
+    TRACE("iface %p, value %#"PRIx64", event %p.\n", iface, value, event);
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if (value <= fence->value)
+    {
+        fence->device->signal_event(event);
+        pthread_mutex_unlock(&fence->mutex);
+        return S_OK;
+    }
+
+    for (i = 0; i < fence->event_count; ++i)
+    {
+        struct vkd3d_waiting_event *current = &fence->events[i];
+        if (current->value == value && current->event == event)
+        {
+            WARN("Event completion for (%p, %#"PRIx64") is already in the list.\n",
+                    event, value);
+            pthread_mutex_unlock(&fence->mutex);
+            return S_OK;
+        }
+    }
+
+    if (!vkd3d_array_reserve((void **)&fence->events, &fence->events_size,
+            fence->event_count + 1, sizeof(*fence->events)))
+    {
+        WARN("Failed to add event.\n");
+        pthread_mutex_unlock(&fence->mutex);
+        return E_OUTOFMEMORY;
+    }
+
+    fence->events[fence->event_count].value = value;
+    fence->events[fence->event_count].event = event;
+    ++fence->event_count;
+
+    pthread_mutex_unlock(&fence->mutex);
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_fence_Signal(ID3D12Fence *iface, UINT64 value)
+{
+    struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
+
+    TRACE("iface %p, value %#"PRIx64".\n", iface, value);
+
+    return d3d12_fence_signal(fence, value, VK_NULL_HANDLE);
+}
+
+static const struct ID3D12FenceVtbl d3d12_fence_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_fence_QueryInterface,
+    d3d12_fence_AddRef,
+    d3d12_fence_Release,
+    /* ID3D12Object methods */
+    d3d12_fence_GetPrivateData,
+    d3d12_fence_SetPrivateData,
+    d3d12_fence_SetPrivateDataInterface,
+    d3d12_fence_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_fence_GetDevice,
+    /* ID3D12Fence methods */
+    d3d12_fence_GetCompletedValue,
+    d3d12_fence_SetEventOnCompletion,
+    d3d12_fence_Signal,
+};
+
+static struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_fence_vtbl);
+    return impl_from_ID3D12Fence(iface);
+}
+
+static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device *device,
+        UINT64 initial_value, D3D12_FENCE_FLAGS flags)
+{
+    HRESULT hr;
+    int rc;
+
+    fence->ID3D12Fence_iface.lpVtbl = &d3d12_fence_vtbl;
+    fence->refcount = 1;
+
+    fence->value = initial_value;
+
+    if ((rc = pthread_mutex_init(&fence->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if (flags)
+        FIXME("Ignoring flags %#x.\n", flags);
+
+    fence->events = NULL;
+    fence->events_size = 0;
+    fence->event_count = 0;
+
+    list_init(&fence->semaphores);
+    fence->semaphore_count = 0;
+
+    memset(fence->old_vk_fences, 0, sizeof(fence->old_vk_fences));
+
+    fence->pending_worker_operation_count = 0;
+
+    if (FAILED(hr = vkd3d_private_store_init(&fence->private_store)))
+    {
+        pthread_mutex_destroy(&fence->mutex);
+        return hr;
+    }
+
+    d3d12_device_add_ref(fence->device = device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_fence_create(struct d3d12_device *device,
+        uint64_t initial_value, D3D12_FENCE_FLAGS flags, struct d3d12_fence **fence)
+{
+    struct d3d12_fence *object;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    d3d12_fence_init(object, device, initial_value, flags);
+
+    TRACE("Created fence %p.\n", object);
+
+    *fence = object;
+
+    return S_OK;
+}
+
+/* Command buffers */
+static void d3d12_command_list_mark_as_invalid(struct d3d12_command_list *list,
+        const char *message, ...)
+{
+    va_list args;
+
+    va_start(args, message);
+    WARN("Command list %p is invalid: \"%s\".\n", list, vkd3d_dbg_vsprintf(message, args));
+    va_end(args);
+
+    list->is_valid = false;
+}
+
+static HRESULT d3d12_command_list_begin_command_buffer(struct d3d12_command_list *list)
+{
+    struct d3d12_device *device = list->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkCommandBufferBeginInfo begin_info;
+    VkResult vr;
+
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    begin_info.pNext = NULL;
+    begin_info.flags = 0;
+    begin_info.pInheritanceInfo = NULL;
+
+    if ((vr = VK_CALL(vkBeginCommandBuffer(list->vk_command_buffer, &begin_info))) < 0)
+    {
+        WARN("Failed to begin command buffer, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    list->is_recording = true;
+    list->is_valid = true;
+
+    return S_OK;
+}
+
+static HRESULT d3d12_command_allocator_allocate_command_buffer(struct d3d12_command_allocator *allocator,
+        struct d3d12_command_list *list)
+{
+    struct d3d12_device *device = allocator->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkCommandBufferAllocateInfo command_buffer_info;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("allocator %p, list %p.\n", allocator, list);
+
+    if (allocator->current_command_list)
+    {
+        WARN("Command allocator is already in use.\n");
+        return E_INVALIDARG;
+    }
+
+    command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    command_buffer_info.pNext = NULL;
+    command_buffer_info.commandPool = allocator->vk_command_pool;
+    command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    command_buffer_info.commandBufferCount = 1;
+
+    if ((vr = VK_CALL(vkAllocateCommandBuffers(device->vk_device, &command_buffer_info,
+            &list->vk_command_buffer))) < 0)
+    {
+        WARN("Failed to allocate Vulkan command buffer, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    list->vk_queue_flags = allocator->vk_queue_flags;
+
+    if (FAILED(hr = d3d12_command_list_begin_command_buffer(list)))
+    {
+        VK_CALL(vkFreeCommandBuffers(device->vk_device, allocator->vk_command_pool,
+                1, &list->vk_command_buffer));
+        return hr;
+    }
+
+    allocator->current_command_list = list;
+
+    return S_OK;
+}
+
+static void d3d12_command_allocator_free_command_buffer(struct d3d12_command_allocator *allocator,
+        struct d3d12_command_list *list)
+{
+    struct d3d12_device *device = allocator->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    TRACE("allocator %p, list %p.\n", allocator, list);
+
+    if (allocator->current_command_list == list)
+        allocator->current_command_list = NULL;
+
+    if (!vkd3d_array_reserve((void **)&allocator->command_buffers, &allocator->command_buffers_size,
+            allocator->command_buffer_count + 1, sizeof(*allocator->command_buffers)))
+    {
+        WARN("Failed to add command buffer.\n");
+        VK_CALL(vkFreeCommandBuffers(device->vk_device, allocator->vk_command_pool,
+                1, &list->vk_command_buffer));
+        return;
+    }
+
+    allocator->command_buffers[allocator->command_buffer_count++] = list->vk_command_buffer;
+}
+
+static bool d3d12_command_allocator_add_render_pass(struct d3d12_command_allocator *allocator, VkRenderPass pass)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->passes, &allocator->passes_size,
+            allocator->pass_count + 1, sizeof(*allocator->passes)))
+        return false;
+
+    allocator->passes[allocator->pass_count++] = pass;
+
+    return true;
+}
+
+static bool d3d12_command_allocator_add_framebuffer(struct d3d12_command_allocator *allocator,
+        VkFramebuffer framebuffer)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->framebuffers, &allocator->framebuffers_size,
+            allocator->framebuffer_count + 1, sizeof(*allocator->framebuffers)))
+        return false;
+
+    allocator->framebuffers[allocator->framebuffer_count++] = framebuffer;
+
+    return true;
+}
+
+static bool d3d12_command_allocator_add_descriptor_pool(struct d3d12_command_allocator *allocator,
+        VkDescriptorPool pool)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->descriptor_pools, &allocator->descriptor_pools_size,
+            allocator->descriptor_pool_count + 1, sizeof(*allocator->descriptor_pools)))
+        return false;
+
+    allocator->descriptor_pools[allocator->descriptor_pool_count++] = pool;
+
+    return true;
+}
+
+static bool d3d12_command_allocator_add_view(struct d3d12_command_allocator *allocator,
+        struct vkd3d_view *view)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->views, &allocator->views_size,
+            allocator->view_count + 1, sizeof(*allocator->views)))
+        return false;
+
+    vkd3d_view_incref(view);
+    allocator->views[allocator->view_count++] = view;
+
+    return true;
+}
+
+static bool d3d12_command_allocator_add_buffer_view(struct d3d12_command_allocator *allocator,
+        VkBufferView view)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->buffer_views, &allocator->buffer_views_size,
+            allocator->buffer_view_count + 1, sizeof(*allocator->buffer_views)))
+        return false;
+
+    allocator->buffer_views[allocator->buffer_view_count++] = view;
+
+    return true;
+}
+
+static bool d3d12_command_allocator_add_transfer_buffer(struct d3d12_command_allocator *allocator,
+        const struct vkd3d_buffer *buffer)
+{
+    if (!vkd3d_array_reserve((void **)&allocator->transfer_buffers, &allocator->transfer_buffers_size,
+            allocator->transfer_buffer_count + 1, sizeof(*allocator->transfer_buffers)))
+        return false;
+
+    allocator->transfer_buffers[allocator->transfer_buffer_count++] = *buffer;
+
+    return true;
+}
+
+static VkDescriptorPool d3d12_command_allocator_allocate_descriptor_pool(
+        struct d3d12_command_allocator *allocator)
+{
+    static const VkDescriptorPoolSize pool_sizes[] =
+    {
+        {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1024},
+        {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1024},
+        {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1024},
+        {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1024},
+        {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1024},
+        {VK_DESCRIPTOR_TYPE_SAMPLER, 1024},
+    };
+    struct d3d12_device *device = allocator->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct VkDescriptorPoolCreateInfo pool_desc;
+    VkDevice vk_device = device->vk_device;
+    VkDescriptorPool vk_pool;
+    VkResult vr;
+
+    if (allocator->free_descriptor_pool_count > 0)
+    {
+        vk_pool = allocator->free_descriptor_pools[allocator->free_descriptor_pool_count - 1];
+        allocator->free_descriptor_pools[allocator->free_descriptor_pool_count - 1] = VK_NULL_HANDLE;
+        --allocator->free_descriptor_pool_count;
+    }
+    else
+    {
+        pool_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+        pool_desc.pNext = NULL;
+        pool_desc.flags = 0;
+        pool_desc.maxSets = 512;
+        pool_desc.poolSizeCount = ARRAY_SIZE(pool_sizes);
+        pool_desc.pPoolSizes = pool_sizes;
+        if ((vr = VK_CALL(vkCreateDescriptorPool(vk_device, &pool_desc, NULL, &vk_pool))) < 0)
+        {
+            ERR("Failed to create descriptor pool, vr %d.\n", vr);
+            return VK_NULL_HANDLE;
+        }
+    }
+
+    if (!(d3d12_command_allocator_add_descriptor_pool(allocator, vk_pool)))
+    {
+        ERR("Failed to add descriptor pool.\n");
+        VK_CALL(vkDestroyDescriptorPool(vk_device, vk_pool, NULL));
+        return VK_NULL_HANDLE;
+    }
+
+    return vk_pool;
+}
+
+static VkDescriptorSet d3d12_command_allocator_allocate_descriptor_set(
+        struct d3d12_command_allocator *allocator, VkDescriptorSetLayout vk_set_layout)
+{
+    struct d3d12_device *device = allocator->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct VkDescriptorSetAllocateInfo set_desc;
+    VkDevice vk_device = device->vk_device;
+    VkDescriptorSet vk_descriptor_set;
+    VkResult vr;
+
+    if (!allocator->vk_descriptor_pool)
+        allocator->vk_descriptor_pool = d3d12_command_allocator_allocate_descriptor_pool(allocator);
+    if (!allocator->vk_descriptor_pool)
+        return VK_NULL_HANDLE;
+
+    set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    set_desc.pNext = NULL;
+    set_desc.descriptorPool = allocator->vk_descriptor_pool;
+    set_desc.descriptorSetCount = 1;
+    set_desc.pSetLayouts = &vk_set_layout;
+    if ((vr = VK_CALL(vkAllocateDescriptorSets(vk_device, &set_desc, &vk_descriptor_set))) >= 0)
+        return vk_descriptor_set;
+
+    allocator->vk_descriptor_pool = VK_NULL_HANDLE;
+    if (vr == VK_ERROR_FRAGMENTED_POOL || vr == VK_ERROR_OUT_OF_POOL_MEMORY_KHR)
+        allocator->vk_descriptor_pool = d3d12_command_allocator_allocate_descriptor_pool(allocator);
+    if (!allocator->vk_descriptor_pool)
+    {
+        ERR("Failed to allocate descriptor set, vr %d.\n", vr);
+        return VK_NULL_HANDLE;
+    }
+
+    set_desc.descriptorPool = allocator->vk_descriptor_pool;
+    if ((vr = VK_CALL(vkAllocateDescriptorSets(vk_device, &set_desc, &vk_descriptor_set))) < 0)
+    {
+        FIXME("Failed to allocate descriptor set from a new pool, vr %d.\n", vr);
+        return VK_NULL_HANDLE;
+    }
+
+    return vk_descriptor_set;
+}
+
+static void d3d12_command_list_allocator_destroyed(struct d3d12_command_list *list)
+{
+    TRACE("list %p.\n", list);
+
+    list->allocator = NULL;
+    list->vk_command_buffer = VK_NULL_HANDLE;
+}
+
+static void vkd3d_buffer_destroy(struct vkd3d_buffer *buffer, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    VK_CALL(vkFreeMemory(device->vk_device, buffer->vk_memory, NULL));
+    VK_CALL(vkDestroyBuffer(device->vk_device, buffer->vk_buffer, NULL));
+}
+
+static void d3d12_command_allocator_free_resources(struct d3d12_command_allocator *allocator,
+        bool keep_reusable_resources)
+{
+    struct d3d12_device *device = allocator->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int i, j;
+
+    allocator->vk_descriptor_pool = VK_NULL_HANDLE;
+
+    if (keep_reusable_resources)
+    {
+        if (vkd3d_array_reserve((void **)&allocator->free_descriptor_pools,
+                &allocator->free_descriptor_pools_size,
+                allocator->free_descriptor_pool_count + allocator->descriptor_pool_count,
+                sizeof(*allocator->free_descriptor_pools)))
+        {
+            for (i = 0, j = allocator->free_descriptor_pool_count; i < allocator->descriptor_pool_count; ++i, ++j)
+            {
+                VK_CALL(vkResetDescriptorPool(device->vk_device, allocator->descriptor_pools[i], 0));
+                allocator->free_descriptor_pools[j] = allocator->descriptor_pools[i];
+            }
+            allocator->free_descriptor_pool_count += allocator->descriptor_pool_count;
+            allocator->descriptor_pool_count = 0;
+        }
+    }
+    else
+    {
+        for (i = 0; i < allocator->free_descriptor_pool_count; ++i)
+        {
+            VK_CALL(vkDestroyDescriptorPool(device->vk_device, allocator->free_descriptor_pools[i], NULL));
+        }
+        allocator->free_descriptor_pool_count = 0;
+    }
+
+    for (i = 0; i < allocator->transfer_buffer_count; ++i)
+    {
+        vkd3d_buffer_destroy(&allocator->transfer_buffers[i], device);
+    }
+    allocator->transfer_buffer_count = 0;
+
+    for (i = 0; i < allocator->buffer_view_count; ++i)
+    {
+        VK_CALL(vkDestroyBufferView(device->vk_device, allocator->buffer_views[i], NULL));
+    }
+    allocator->buffer_view_count = 0;
+
+    for (i = 0; i < allocator->view_count; ++i)
+    {
+        vkd3d_view_decref(allocator->views[i], device);
+    }
+    allocator->view_count = 0;
+
+    for (i = 0; i < allocator->descriptor_pool_count; ++i)
+    {
+        VK_CALL(vkDestroyDescriptorPool(device->vk_device, allocator->descriptor_pools[i], NULL));
+    }
+    allocator->descriptor_pool_count = 0;
+
+    for (i = 0; i < allocator->framebuffer_count; ++i)
+    {
+        VK_CALL(vkDestroyFramebuffer(device->vk_device, allocator->framebuffers[i], NULL));
+    }
+    allocator->framebuffer_count = 0;
+
+    for (i = 0; i < allocator->pass_count; ++i)
+    {
+        VK_CALL(vkDestroyRenderPass(device->vk_device, allocator->passes[i], NULL));
+    }
+    allocator->pass_count = 0;
+}
+
+/* ID3D12CommandAllocator */
+static inline struct d3d12_command_allocator *impl_from_ID3D12CommandAllocator(ID3D12CommandAllocator *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_command_allocator, ID3D12CommandAllocator_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_QueryInterface(ID3D12CommandAllocator *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12CommandAllocator)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12CommandAllocator_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_allocator_AddRef(ID3D12CommandAllocator *iface)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+    ULONG refcount = InterlockedIncrement(&allocator->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", allocator, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_allocator_Release(ID3D12CommandAllocator *iface)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+    ULONG refcount = InterlockedDecrement(&allocator->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", allocator, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = allocator->device;
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        vkd3d_private_store_destroy(&allocator->private_store);
+
+        if (allocator->current_command_list)
+            d3d12_command_list_allocator_destroyed(allocator->current_command_list);
+
+        d3d12_command_allocator_free_resources(allocator, false);
+        vkd3d_free(allocator->transfer_buffers);
+        vkd3d_free(allocator->buffer_views);
+        vkd3d_free(allocator->views);
+        vkd3d_free(allocator->descriptor_pools);
+        vkd3d_free(allocator->free_descriptor_pools);
+        vkd3d_free(allocator->framebuffers);
+        vkd3d_free(allocator->passes);
+
+        /* All command buffers are implicitly freed when a pool is destroyed. */
+        vkd3d_free(allocator->command_buffers);
+        VK_CALL(vkDestroyCommandPool(device->vk_device, allocator->vk_command_pool, NULL));
+
+        vkd3d_free(allocator);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_GetPrivateData(ID3D12CommandAllocator *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&allocator->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_SetPrivateData(ID3D12CommandAllocator *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&allocator->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_SetPrivateDataInterface(ID3D12CommandAllocator *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&allocator->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_SetName(ID3D12CommandAllocator *iface, const WCHAR *name)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, allocator->device->wchar_size));
+
+    return vkd3d_set_vk_object_name(allocator->device, (uint64_t)allocator->vk_command_pool,
+            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, name);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_GetDevice(ID3D12CommandAllocator *iface, REFIID iid, void **device)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(allocator->device, iid, device);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_Reset(ID3D12CommandAllocator *iface)
+{
+    struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_command_list *list;
+    struct d3d12_device *device;
+    VkResult vr;
+
+    TRACE("iface %p.\n", iface);
+
+    if ((list = allocator->current_command_list))
+    {
+        if (list->is_recording)
+        {
+            WARN("A command list using this allocator is in the recording state.\n");
+            return E_FAIL;
+        }
+
+        TRACE("Resetting command list %p.\n", list);
+    }
+
+    device = allocator->device;
+    vk_procs = &device->vk_procs;
+
+    d3d12_command_allocator_free_resources(allocator, true);
+    if (allocator->command_buffer_count)
+    {
+        VK_CALL(vkFreeCommandBuffers(device->vk_device, allocator->vk_command_pool,
+                allocator->command_buffer_count, allocator->command_buffers));
+        allocator->command_buffer_count = 0;
+    }
+
+    /* The intent here is to recycle memory, so do not use RELEASE_RESOURCES_BIT here. */
+    if ((vr = VK_CALL(vkResetCommandPool(device->vk_device, allocator->vk_command_pool, 0))))
+    {
+        WARN("Resetting command pool failed, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    return S_OK;
+}
+
+static const struct ID3D12CommandAllocatorVtbl d3d12_command_allocator_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_command_allocator_QueryInterface,
+    d3d12_command_allocator_AddRef,
+    d3d12_command_allocator_Release,
+    /* ID3D12Object methods */
+    d3d12_command_allocator_GetPrivateData,
+    d3d12_command_allocator_SetPrivateData,
+    d3d12_command_allocator_SetPrivateDataInterface,
+    d3d12_command_allocator_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_command_allocator_GetDevice,
+    /* ID3D12CommandAllocator methods */
+    d3d12_command_allocator_Reset,
+};
+
+static struct d3d12_command_allocator *unsafe_impl_from_ID3D12CommandAllocator(ID3D12CommandAllocator *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_command_allocator_vtbl);
+    return impl_from_ID3D12CommandAllocator(iface);
+}
+
+struct vkd3d_queue *d3d12_device_get_vkd3d_queue(struct d3d12_device *device,
+        D3D12_COMMAND_LIST_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_COMMAND_LIST_TYPE_DIRECT:
+            return device->direct_queue;
+        case D3D12_COMMAND_LIST_TYPE_COMPUTE:
+            return device->compute_queue;
+        case D3D12_COMMAND_LIST_TYPE_COPY:
+            return device->copy_queue;
+        default:
+            FIXME("Unhandled command list type %#x.\n", type);
+            return NULL;
+    }
+}
+
+static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allocator,
+        struct d3d12_device *device, D3D12_COMMAND_LIST_TYPE type)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkCommandPoolCreateInfo command_pool_info;
+    struct vkd3d_queue *queue;
+    VkResult vr;
+    HRESULT hr;
+
+    if (FAILED(hr = vkd3d_private_store_init(&allocator->private_store)))
+        return hr;
+
+    if (!(queue = d3d12_device_get_vkd3d_queue(device, type)))
+        queue = device->direct_queue;
+
+    allocator->ID3D12CommandAllocator_iface.lpVtbl = &d3d12_command_allocator_vtbl;
+    allocator->refcount = 1;
+
+    allocator->type = type;
+    allocator->vk_queue_flags = queue->vk_queue_flags;
+
+    command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    command_pool_info.pNext = NULL;
+    /* Do not use RESET_COMMAND_BUFFER_BIT. This allows the CommandPool to be a D3D12-style command pool.
+     * Memory is owned by the pool and CommandBuffers become lightweight handles,
+     * assuming a half-decent driver implementation. */
+    command_pool_info.flags = 0;
+    command_pool_info.queueFamilyIndex = queue->vk_family_index;
+
+    if ((vr = VK_CALL(vkCreateCommandPool(device->vk_device, &command_pool_info, NULL,
+            &allocator->vk_command_pool))) < 0)
+    {
+        WARN("Failed to create Vulkan command pool, vr %d.\n", vr);
+        vkd3d_private_store_destroy(&allocator->private_store);
+        return hresult_from_vk_result(vr);
+    }
+
+    allocator->vk_descriptor_pool = VK_NULL_HANDLE;
+
+    allocator->free_descriptor_pools = NULL;
+    allocator->free_descriptor_pools_size = 0;
+    allocator->free_descriptor_pool_count = 0;
+
+    allocator->passes = NULL;
+    allocator->passes_size = 0;
+    allocator->pass_count = 0;
+
+    allocator->framebuffers = NULL;
+    allocator->framebuffers_size = 0;
+    allocator->framebuffer_count = 0;
+
+    allocator->descriptor_pools = NULL;
+    allocator->descriptor_pools_size = 0;
+    allocator->descriptor_pool_count = 0;
+
+    allocator->views = NULL;
+    allocator->views_size = 0;
+    allocator->view_count = 0;
+
+    allocator->buffer_views = NULL;
+    allocator->buffer_views_size = 0;
+    allocator->buffer_view_count = 0;
+
+    allocator->transfer_buffers = NULL;
+    allocator->transfer_buffers_size = 0;
+    allocator->transfer_buffer_count = 0;
+
+    allocator->command_buffers = NULL;
+    allocator->command_buffers_size = 0;
+    allocator->command_buffer_count = 0;
+
+    allocator->current_command_list = NULL;
+
+    d3d12_device_add_ref(allocator->device = device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_command_allocator_create(struct d3d12_device *device,
+        D3D12_COMMAND_LIST_TYPE type, struct d3d12_command_allocator **allocator)
+{
+    struct d3d12_command_allocator *object;
+    HRESULT hr;
+
+    if (!(D3D12_COMMAND_LIST_TYPE_DIRECT <= type && type <= D3D12_COMMAND_LIST_TYPE_COPY))
+    {
+        WARN("Invalid type %#x.\n", type);
+        return E_INVALIDARG;
+    }
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_command_allocator_init(object, device, type)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created command allocator %p.\n", object);
+
+    *allocator = object;
+
+    return S_OK;
+}
+
+/* ID3D12CommandList */
+static inline struct d3d12_command_list *impl_from_ID3D12GraphicsCommandList2(ID3D12GraphicsCommandList2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList2_iface);
+}
+
+static void d3d12_command_list_invalidate_current_framebuffer(struct d3d12_command_list *list)
+{
+    list->current_framebuffer = VK_NULL_HANDLE;
+}
+
+static void d3d12_command_list_invalidate_current_pipeline(struct d3d12_command_list *list)
+{
+    list->current_pipeline = VK_NULL_HANDLE;
+}
+
+static void d3d12_command_list_end_current_render_pass(struct d3d12_command_list *list)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+
+    if (list->xfb_enabled)
+    {
+        VK_CALL(vkCmdEndTransformFeedbackEXT(list->vk_command_buffer, 0, ARRAY_SIZE(list->so_counter_buffers),
+                list->so_counter_buffers, list->so_counter_buffer_offsets));
+    }
+
+    if (list->current_render_pass)
+        VK_CALL(vkCmdEndRenderPass(list->vk_command_buffer));
+
+    list->current_render_pass = VK_NULL_HANDLE;
+
+    if (list->xfb_enabled)
+    {
+        VkMemoryBarrier vk_barrier;
+
+        /* We need a barrier between pause and resume. */
+        vk_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+        vk_barrier.pNext = NULL;
+        vk_barrier.srcAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
+        vk_barrier.dstAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
+        VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,
+                VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0,
+                1, &vk_barrier, 0, NULL, 0, NULL));
+
+        list->xfb_enabled = false;
+    }
+}
+
+static void d3d12_command_list_invalidate_current_render_pass(struct d3d12_command_list *list)
+{
+    d3d12_command_list_end_current_render_pass(list);
+}
+
+static void d3d12_command_list_invalidate_bindings(struct d3d12_command_list *list,
+        struct d3d12_pipeline_state *state)
+{
+    if (state && state->uav_counter_count)
+    {
+        enum vkd3d_pipeline_bind_point bind_point = (enum vkd3d_pipeline_bind_point)state->vk_bind_point;
+        struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+
+        vkd3d_array_reserve((void **)&bindings->vk_uav_counter_views, &bindings->vk_uav_counter_views_size,
+                state->uav_counter_count, sizeof(*bindings->vk_uav_counter_views));
+        bindings->uav_counters_dirty = true;
+    }
+}
+
+static void d3d12_command_list_invalidate_root_parameters(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+
+    if (!bindings->root_signature)
+        return;
+
+    bindings->descriptor_set = VK_NULL_HANDLE;
+    bindings->descriptor_table_dirty_mask = bindings->descriptor_table_active_mask & bindings->root_signature->descriptor_table_mask;
+    bindings->push_descriptor_dirty_mask = bindings->push_descriptor_active_mask & bindings->root_signature->push_descriptor_mask;
+}
+
+static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, unsigned int stencil_state,
+        const struct d3d12_resource *resource, VkQueueFlags vk_queue_flags, const struct vkd3d_vulkan_info *vk_info,
+        VkAccessFlags *access_mask, VkPipelineStageFlags *stage_flags, VkImageLayout *image_layout)
+{
+    bool is_swapchain_image = resource && (resource->flags & VKD3D_RESOURCE_PRESENT_STATE_TRANSITION);
+    VkPipelineStageFlags queue_shader_stages = 0;
+
+    if (vk_queue_flags & VK_QUEUE_GRAPHICS_BIT)
+    {
+        queue_shader_stages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
+                | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
+                | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT
+                | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
+                | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+    }
+    if (vk_queue_flags & VK_QUEUE_COMPUTE_BIT)
+        queue_shader_stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+
+    switch (state)
+    {
+        case D3D12_RESOURCE_STATE_COMMON: /* D3D12_RESOURCE_STATE_PRESENT */
+            /* The COMMON state is used for ownership transfer between
+             * DIRECT/COMPUTE and COPY queues. Additionally, a texture has to
+             * be in the COMMON state to be accessed by CPU. Moreover,
+             * resources can be implicitly promoted to other states out of the
+             * COMMON state, and the resource state can decay to the COMMON
+             * state when GPU finishes execution of a command list. */
+            if (is_swapchain_image)
+            {
+                if (resource->present_state == D3D12_RESOURCE_STATE_PRESENT)
+                {
+                    *access_mask = VK_ACCESS_MEMORY_READ_BIT;
+                    *stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+                    if (image_layout)
+                        *image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+                    return true;
+                }
+                else if (resource->present_state != D3D12_RESOURCE_STATE_COMMON)
+                {
+                    vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, 0,
+                            resource, vk_queue_flags, vk_info, access_mask, stage_flags, image_layout);
+                    return true;
+                }
+            }
+
+            *access_mask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
+            *stage_flags = VK_PIPELINE_STAGE_HOST_BIT;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_GENERAL;
+            return true;
+
+        /* Handle write states. */
+        case D3D12_RESOURCE_STATE_RENDER_TARGET:
+            *access_mask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+                    | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+            *stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+            return true;
+
+        case D3D12_RESOURCE_STATE_UNORDERED_ACCESS:
+            *access_mask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+            *stage_flags = queue_shader_stages;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_GENERAL;
+            return true;
+
+        case D3D12_RESOURCE_STATE_DEPTH_WRITE:
+            *access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
+                    | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+            *stage_flags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+                    | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+            if (image_layout)
+            {
+                if (!stencil_state || (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE))
+                    *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+                else
+                    *image_layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
+            }
+            return true;
+
+        case D3D12_RESOURCE_STATE_COPY_DEST:
+        case D3D12_RESOURCE_STATE_RESOLVE_DEST:
+            *access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
+            *stage_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+            return true;
+
+        case D3D12_RESOURCE_STATE_STREAM_OUT:
+            *access_mask = VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT
+                    | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
+                    | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
+            *stage_flags = VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
+                    | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
+            return true;
+
+        /* Set the Vulkan image layout for read-only states. */
+        case D3D12_RESOURCE_STATE_DEPTH_READ:
+        case D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE:
+        case D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
+        case D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
+                | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
+            *access_mask = 0;
+            *stage_flags = 0;
+            if (image_layout)
+            {
+                if (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE)
+                {
+                    *image_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
+                    *access_mask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+                }
+                else
+                {
+                    *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
+                }
+            }
+            break;
+
+        case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
+        case D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE:
+        case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE:
+            *access_mask = 0;
+            *stage_flags = 0;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+            break;
+
+        case D3D12_RESOURCE_STATE_COPY_SOURCE:
+        case D3D12_RESOURCE_STATE_RESOLVE_SOURCE:
+            *access_mask = 0;
+            *stage_flags = 0;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+            break;
+
+        default:
+            *access_mask = 0;
+            *stage_flags = 0;
+            if (image_layout)
+                *image_layout = VK_IMAGE_LAYOUT_GENERAL;
+            break;
+    }
+
+    /* Handle read-only states. */
+    assert(!is_write_resource_state(state));
+
+    if (state & D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)
+    {
+        *access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
+                | VK_ACCESS_UNIFORM_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
+                | queue_shader_stages;
+        state &= ~D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+    }
+
+    if (state & D3D12_RESOURCE_STATE_INDEX_BUFFER)
+    {
+        *access_mask |= VK_ACCESS_INDEX_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+        state &= ~D3D12_RESOURCE_STATE_INDEX_BUFFER;
+    }
+
+    if (state & D3D12_RESOURCE_STATE_DEPTH_READ)
+    {
+        *access_mask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+                | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+        state &= ~D3D12_RESOURCE_STATE_DEPTH_READ;
+    }
+
+    if (state & D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)
+    {
+        *access_mask |= VK_ACCESS_SHADER_READ_BIT;
+        *stage_flags |= (queue_shader_stages & ~VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+        state &= ~D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+    }
+    if (state & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
+    {
+        *access_mask |= VK_ACCESS_SHADER_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+        state &= ~D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+    }
+
+    if (state & D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT) /* D3D12_RESOURCE_STATE_PREDICATION */
+    {
+        *access_mask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+        if (vk_info->EXT_conditional_rendering)
+        {
+            *access_mask |= VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT;
+            *stage_flags |= VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT;
+        }
+        state &= ~D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
+    }
+
+    if (state & (D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_RESOLVE_SOURCE))
+    {
+        *access_mask |= VK_ACCESS_TRANSFER_READ_BIT;
+        *stage_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+        state &= ~(D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
+    }
+
+    if (state)
+    {
+        WARN("Invalid resource state %#x.\n", state);
+        return false;
+    }
+    return true;
+}
+
+static void d3d12_command_list_transition_resource_to_initial_state(struct d3d12_command_list *list,
+        struct d3d12_resource *resource)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info;
+    VkPipelineStageFlags src_stage_mask, dst_stage_mask;
+    const struct vkd3d_format *format;
+    VkImageMemoryBarrier barrier;
+
+    assert(d3d12_resource_is_texture(resource));
+
+    if (!(format = vkd3d_format_from_d3d12_resource_desc(list->device, &resource->desc, 0)))
+    {
+        ERR("Resource %p has invalid format %#x.\n", resource, resource->desc.Format);
+        return;
+    }
+
+    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barrier.pNext = NULL;
+
+    /* vkQueueSubmit() defines a memory dependency with prior host writes. */
+    src_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+    barrier.srcAccessMask = 0;
+    barrier.oldLayout = d3d12_resource_is_cpu_accessible(resource) ?
+            VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED;
+
+    if (!vk_barrier_parameters_from_d3d12_resource_state(resource->initial_state, 0,
+            resource, list->vk_queue_flags, vk_info, &barrier.dstAccessMask, &dst_stage_mask, &barrier.newLayout))
+    {
+        FIXME("Unhandled state %#x.\n", resource->initial_state);
+        return;
+    }
+
+    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.image = resource->u.vk_image;
+    barrier.subresourceRange.aspectMask = format->vk_aspect_mask;
+    barrier.subresourceRange.baseMipLevel = 0;
+    barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+    barrier.subresourceRange.baseArrayLayer = 0;
+    barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+
+    TRACE("Initial state %#x transition for resource %p (old layout %#x, new layout %#x).\n",
+            resource->initial_state, resource, barrier.oldLayout, barrier.newLayout);
+
+    VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, src_stage_mask, dst_stage_mask, 0,
+            0, NULL, 0, NULL, 1, &barrier));
+}
+
+static void d3d12_command_list_track_resource_usage(struct d3d12_command_list *list,
+        struct d3d12_resource *resource)
+{
+    if (resource->flags & VKD3D_RESOURCE_INITIAL_STATE_TRANSITION)
+    {
+        d3d12_command_list_end_current_render_pass(list);
+
+        d3d12_command_list_transition_resource_to_initial_state(list, resource);
+        resource->flags &= ~VKD3D_RESOURCE_INITIAL_STATE_TRANSITION;
+    }
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12GraphicsCommandList2 *iface,
+        REFIID iid, void **object)
+{
+    TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
+
+    if (IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList2)
+            || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList1)
+            || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList)
+            || IsEqualGUID(iid, &IID_ID3D12CommandList)
+            || IsEqualGUID(iid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(iid, &IID_ID3D12Object)
+            || IsEqualGUID(iid, &IID_IUnknown))
+    {
+        ID3D12GraphicsCommandList2_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_list_AddRef(ID3D12GraphicsCommandList2 *iface)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    ULONG refcount = InterlockedIncrement(&list->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", list, refcount);
+
+    return refcount;
+}
+
+static void vkd3d_pipeline_bindings_cleanup(struct vkd3d_pipeline_bindings *bindings)
+{
+    vkd3d_free(bindings->vk_uav_counter_views);
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandList2 *iface)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    ULONG refcount = InterlockedDecrement(&list->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", list, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = list->device;
+
+        vkd3d_private_store_destroy(&list->private_store);
+
+        /* When command pool is destroyed, all command buffers are implicitly freed. */
+        if (list->allocator)
+            d3d12_command_allocator_free_command_buffer(list->allocator, list);
+
+        vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE]);
+        vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS]);
+
+        vkd3d_free(list);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetPrivateData(ID3D12GraphicsCommandList2 *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&list->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateData(ID3D12GraphicsCommandList2 *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&list->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateDataInterface(ID3D12GraphicsCommandList2 *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&list->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetName(ID3D12GraphicsCommandList2 *iface, const WCHAR *name)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, list->device->wchar_size));
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetDevice(ID3D12GraphicsCommandList2 *iface, REFIID iid, void **device)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(list->device, iid, device);
+}
+
+static D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE d3d12_command_list_GetType(ID3D12GraphicsCommandList2 *iface)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return list->type;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandList2 *iface)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkResult vr;
+
+    TRACE("iface %p.\n", iface);
+
+    if (!list->is_recording)
+    {
+        WARN("Command list is not in the recording state.\n");
+        return E_FAIL;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    d3d12_command_list_end_current_render_pass(list);
+    if (list->is_predicated)
+        VK_CALL(vkCmdEndConditionalRenderingEXT(list->vk_command_buffer));
+
+    if ((vr = VK_CALL(vkEndCommandBuffer(list->vk_command_buffer))) < 0)
+    {
+        WARN("Failed to end command buffer, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    if (list->allocator)
+    {
+        d3d12_command_allocator_free_command_buffer(list->allocator, list);
+        list->allocator = NULL;
+    }
+
+    list->is_recording = false;
+
+    if (!list->is_valid)
+    {
+        WARN("Error occurred during command list recording.\n");
+        return E_INVALIDARG;
+    }
+
+    return S_OK;
+}
+
+static void d3d12_command_list_reset_state(struct d3d12_command_list *list,
+        ID3D12PipelineState *initial_pipeline_state)
+{
+    ID3D12GraphicsCommandList2 *iface = &list->ID3D12GraphicsCommandList2_iface;
+
+    memset(list->strides, 0, sizeof(list->strides));
+    list->primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
+
+    list->index_buffer_format = DXGI_FORMAT_UNKNOWN;
+
+    memset(list->rtvs, 0, sizeof(list->rtvs));
+    list->dsv = VK_NULL_HANDLE;
+    list->dsv_format = VK_FORMAT_UNDEFINED;
+    list->fb_width = 0;
+    list->fb_height = 0;
+    list->fb_layer_count = 0;
+
+    list->xfb_enabled = false;
+
+    list->is_predicated = false;
+
+    list->current_framebuffer = VK_NULL_HANDLE;
+    list->current_pipeline = VK_NULL_HANDLE;
+    list->pso_render_pass = VK_NULL_HANDLE;
+    list->current_render_pass = VK_NULL_HANDLE;
+
+    vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE]);
+    vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS]);
+    memset(list->pipeline_bindings, 0, sizeof(list->pipeline_bindings));
+    list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS].vk_bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE].vk_bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
+
+    list->state = NULL;
+
+    memset(list->so_counter_buffers, 0, sizeof(list->so_counter_buffers));
+    memset(list->so_counter_buffer_offsets, 0, sizeof(list->so_counter_buffer_offsets));
+
+    ID3D12GraphicsCommandList2_SetPipelineState(iface, initial_pipeline_state);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_Reset(ID3D12GraphicsCommandList2 *iface,
+        ID3D12CommandAllocator *allocator, ID3D12PipelineState *initial_pipeline_state)
+{
+    struct d3d12_command_allocator *allocator_impl = unsafe_impl_from_ID3D12CommandAllocator(allocator);
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    HRESULT hr;
+
+    TRACE("iface %p, allocator %p, initial_pipeline_state %p.\n",
+            iface, allocator, initial_pipeline_state);
+
+    if (!allocator_impl)
+    {
+        WARN("Command allocator is NULL.\n");
+        return E_INVALIDARG;
+    }
+
+    if (list->is_recording)
+    {
+        WARN("Command list is in the recording state.\n");
+        return E_FAIL;
+    }
+
+    if (SUCCEEDED(hr = d3d12_command_allocator_allocate_command_buffer(allocator_impl, list)))
+    {
+        list->allocator = allocator_impl;
+        d3d12_command_list_reset_state(list, initial_pipeline_state);
+    }
+
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_list_ClearState(ID3D12GraphicsCommandList2 *iface,
+        ID3D12PipelineState *pipeline_state)
+{
+    FIXME("iface %p, pipline_state %p stub!\n", iface, pipeline_state);
+
+    return E_NOTIMPL;
+}
+
+static bool d3d12_command_list_has_depth_stencil_view(struct d3d12_command_list *list)
+{
+    struct d3d12_graphics_pipeline_state *graphics;
+
+    assert(d3d12_pipeline_state_is_graphics(list->state));
+    graphics = &list->state->u.graphics;
+
+    return graphics->dsv_format || (d3d12_pipeline_state_has_unknown_dsv_format(list->state) && list->dsv_format);
+}
+
+static void d3d12_command_list_get_fb_extent(struct d3d12_command_list *list,
+        uint32_t *width, uint32_t *height, uint32_t *layer_count)
+{
+    struct d3d12_graphics_pipeline_state *graphics = &list->state->u.graphics;
+    struct d3d12_device *device = list->device;
+
+    if (graphics->rt_count || d3d12_command_list_has_depth_stencil_view(list))
+    {
+        *width = list->fb_width;
+        *height = list->fb_height;
+        if (layer_count)
+            *layer_count = list->fb_layer_count;
+    }
+    else
+    {
+        *width = device->vk_info.device_limits.maxFramebufferWidth;
+        *height = device->vk_info.device_limits.maxFramebufferHeight;
+        if (layer_count)
+            *layer_count = 1;
+    }
+}
+
+static bool d3d12_command_list_update_current_framebuffer(struct d3d12_command_list *list)
+{
+    struct d3d12_device *device = list->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkImageView views[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
+    struct d3d12_graphics_pipeline_state *graphics;
+    struct VkFramebufferCreateInfo fb_desc;
+    VkFramebuffer vk_framebuffer;
+    unsigned int view_count;
+    unsigned int i;
+    VkResult vr;
+
+    if (list->current_framebuffer != VK_NULL_HANDLE)
+        return true;
+
+    graphics = &list->state->u.graphics;
+
+    for (i = 0, view_count = 0; i < graphics->rt_count; ++i)
+    {
+        if (graphics->null_attachment_mask & (1u << i))
+        {
+            if (list->rtvs[i])
+                WARN("Expected NULL RTV for attachment %u.\n", i);
+            continue;
+        }
+
+        if (!list->rtvs[i])
+        {
+            FIXME("Invalid RTV for attachment %u.\n", i);
+            return false;
+        }
+
+        views[view_count++] = list->rtvs[i];
+    }
+
+    if (d3d12_command_list_has_depth_stencil_view(list))
+    {
+        if (!(views[view_count++] = list->dsv))
+        {
+            FIXME("Invalid DSV.\n");
+            return false;
+        }
+    }
+
+    fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    fb_desc.pNext = NULL;
+    fb_desc.flags = 0;
+    fb_desc.renderPass = list->pso_render_pass;
+    fb_desc.attachmentCount = view_count;
+    fb_desc.pAttachments = views;
+    d3d12_command_list_get_fb_extent(list, &fb_desc.width, &fb_desc.height, &fb_desc.layers);
+    if ((vr = VK_CALL(vkCreateFramebuffer(device->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0)
+    {
+        WARN("Failed to create Vulkan framebuffer, vr %d.\n", vr);
+        return false;
+    }
+
+    if (!d3d12_command_allocator_add_framebuffer(list->allocator, vk_framebuffer))
+    {
+        WARN("Failed to add framebuffer.\n");
+        VK_CALL(vkDestroyFramebuffer(device->vk_device, vk_framebuffer, NULL));
+        return false;
+    }
+
+    list->current_framebuffer = vk_framebuffer;
+
+    return true;
+}
+
+static bool d3d12_command_list_update_compute_pipeline(struct d3d12_command_list *list)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+
+    if (list->current_pipeline != VK_NULL_HANDLE)
+        return true;
+
+    if (!d3d12_pipeline_state_is_compute(list->state))
+    {
+        WARN("Pipeline state %p is not a compute pipeline.\n", list->state);
+        return false;
+    }
+
+    VK_CALL(vkCmdBindPipeline(list->vk_command_buffer, list->state->vk_bind_point, list->state->u.compute.vk_pipeline));
+    list->current_pipeline = list->state->u.compute.vk_pipeline;
+
+    return true;
+}
+
+static bool d3d12_command_list_update_graphics_pipeline(struct d3d12_command_list *list)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    VkRenderPass vk_render_pass;
+    VkPipeline vk_pipeline;
+
+    if (list->current_pipeline != VK_NULL_HANDLE)
+        return true;
+
+    if (!d3d12_pipeline_state_is_graphics(list->state))
+    {
+        WARN("Pipeline state %p is not a graphics pipeline.\n", list->state);
+        return false;
+    }
+
+    if (!(vk_pipeline = d3d12_pipeline_state_get_or_create_pipeline(list->state,
+            list->primitive_topology, list->strides, list->dsv_format, &vk_render_pass)))
+        return false;
+
+    /* The render pass cache ensures that we use the same Vulkan render pass
+     * object for compatible render passes. */
+    if (list->pso_render_pass != vk_render_pass)
+    {
+        list->pso_render_pass = vk_render_pass;
+        d3d12_command_list_invalidate_current_framebuffer(list);
+        d3d12_command_list_invalidate_current_render_pass(list);
+    }
+
+    VK_CALL(vkCmdBindPipeline(list->vk_command_buffer, list->state->vk_bind_point, vk_pipeline));
+    list->current_pipeline = vk_pipeline;
+
+    return true;
+}
+
+static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+
+    if (bindings->descriptor_set && !bindings->in_use)
+        return;
+
+    /* We cannot modify bound descriptor sets. We need a new descriptor set if
+     * we are about to update resource bindings.
+     *
+     * The Vulkan spec says:
+     *
+     *   "The descriptor set contents bound by a call to
+     *   vkCmdBindDescriptorSets may be consumed during host execution of the
+     *   command, or during shader execution of the resulting draws, or any
+     *   time in between. Thus, the contents must not be altered (overwritten
+     *   by an update command, or freed) between when the command is recorded
+     *   and when the command completes executing on the queue."
+     */
+    bindings->descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator,
+            root_signature->vk_set_layout);
+    bindings->in_use = false;
+
+    bindings->descriptor_table_dirty_mask |= bindings->descriptor_table_active_mask & root_signature->descriptor_table_mask;
+    bindings->push_descriptor_dirty_mask |= bindings->push_descriptor_active_mask & root_signature->push_descriptor_mask;
+}
+
+static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write,
+        VkDescriptorImageInfo *vk_image_info, const struct d3d12_desc *descriptor,
+        uint32_t descriptor_range_magic, VkDescriptorSet vk_descriptor_set,
+        uint32_t vk_binding, unsigned int index)
+{
+    const struct vkd3d_view *view = descriptor->u.view;
+
+    if (descriptor->magic != descriptor_range_magic)
+        return false;
+
+    vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    vk_descriptor_write->pNext = NULL;
+    vk_descriptor_write->dstSet = vk_descriptor_set;
+    vk_descriptor_write->dstBinding = vk_binding + index;
+    vk_descriptor_write->dstArrayElement = 0;
+    vk_descriptor_write->descriptorCount = 1;
+    vk_descriptor_write->descriptorType = descriptor->vk_descriptor_type;
+    vk_descriptor_write->pImageInfo = NULL;
+    vk_descriptor_write->pBufferInfo = NULL;
+    vk_descriptor_write->pTexelBufferView = NULL;
+
+    switch (descriptor->magic)
+    {
+        case VKD3D_DESCRIPTOR_MAGIC_CBV:
+            vk_descriptor_write->pBufferInfo = &descriptor->u.vk_cbv_info;
+            break;
+
+        case VKD3D_DESCRIPTOR_MAGIC_SRV:
+        case VKD3D_DESCRIPTOR_MAGIC_UAV:
+            /* We use separate bindings for buffer and texture SRVs/UAVs.
+             * See d3d12_root_signature_init(). */
+            vk_descriptor_write->dstBinding = vk_binding + 2 * index;
+            if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+                    && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+                ++vk_descriptor_write->dstBinding;
+
+            if (descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+                    || descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+            {
+                vk_descriptor_write->pTexelBufferView = &view->u.vk_buffer_view;
+            }
+            else
+            {
+                vk_image_info->sampler = VK_NULL_HANDLE;
+                vk_image_info->imageView = view->u.vk_image_view;
+                vk_image_info->imageLayout = descriptor->magic == VKD3D_DESCRIPTOR_MAGIC_SRV
+                        ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
+
+                vk_descriptor_write->pImageInfo = vk_image_info;
+            }
+            break;
+
+        case VKD3D_DESCRIPTOR_MAGIC_SAMPLER:
+            vk_image_info->sampler = view->u.vk_sampler;
+            vk_image_info->imageView = VK_NULL_HANDLE;
+            vk_image_info->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+            vk_descriptor_write->pImageInfo = vk_image_info;
+            break;
+
+        default:
+            ERR("Invalid descriptor %#x.\n", descriptor->magic);
+            return false;
+    }
+
+    return true;
+}
+
+static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, unsigned int index, struct d3d12_desc *base_descriptor)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    struct VkWriteDescriptorSet descriptor_writes[24], *current_descriptor_write;
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    struct VkDescriptorImageInfo image_infos[24], *current_image_info;
+    const struct d3d12_root_descriptor_table *descriptor_table;
+    const struct d3d12_pipeline_state *state = list->state;
+    const struct d3d12_root_descriptor_table_range *range;
+    VkDevice vk_device = list->device->vk_device;
+    unsigned int i, j, k, descriptor_count;
+    struct d3d12_desc *descriptor;
+
+    descriptor_table = root_signature_get_descriptor_table(root_signature, index);
+
+    descriptor = base_descriptor;
+    descriptor_count = 0;
+    current_descriptor_write = descriptor_writes;
+    current_image_info = image_infos;
+    for (i = 0; i < descriptor_table->range_count; ++i)
+    {
+        range = &descriptor_table->ranges[i];
+
+        if (range->offset != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
+        {
+            descriptor = base_descriptor + range->offset;
+        }
+
+        for (j = 0; j < range->descriptor_count; ++j, ++descriptor)
+        {
+            unsigned int register_idx = range->base_register_idx + j;
+
+            /* Track UAV counters. */
+            if (range->descriptor_magic == VKD3D_DESCRIPTOR_MAGIC_UAV)
+            {
+                for (k = 0; k < state->uav_counter_count; ++k)
+                {
+                    if (state->uav_counters[k].register_space == range->register_space
+                            && state->uav_counters[k].register_index == register_idx)
+                    {
+                        VkBufferView vk_counter_view = descriptor->magic == VKD3D_DESCRIPTOR_MAGIC_UAV
+                                ? descriptor->u.view->vk_counter_view : VK_NULL_HANDLE;
+                        if (bindings->vk_uav_counter_views[k] != vk_counter_view)
+                            bindings->uav_counters_dirty = true;
+                        bindings->vk_uav_counter_views[k] = vk_counter_view;
+                        break;
+                    }
+                }
+            }
+
+            if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write,
+                    current_image_info, descriptor, range->descriptor_magic,
+                    bindings->descriptor_set, range->binding, j))
+                continue;
+
+            ++descriptor_count;
+            ++current_descriptor_write;
+            ++current_image_info;
+
+            if (descriptor_count == ARRAY_SIZE(descriptor_writes))
+            {
+                VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL));
+                descriptor_count = 0;
+                current_descriptor_write = descriptor_writes;
+                current_image_info = image_infos;
+            }
+        }
+    }
+
+    VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL));
+}
+
+static bool vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet *vk_descriptor_write,
+        const struct d3d12_root_parameter *root_parameter, VkDescriptorSet vk_descriptor_set,
+        VkBufferView *vk_buffer_view, const VkDescriptorBufferInfo *vk_buffer_info)
+{
+    const struct d3d12_root_descriptor *root_descriptor;
+
+    switch (root_parameter->parameter_type)
+    {
+        case D3D12_ROOT_PARAMETER_TYPE_CBV:
+            vk_descriptor_write->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+            break;
+        case D3D12_ROOT_PARAMETER_TYPE_SRV:
+            vk_descriptor_write->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+            break;
+        case D3D12_ROOT_PARAMETER_TYPE_UAV:
+            vk_descriptor_write->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+            break;
+        default:
+            ERR("Invalid root descriptor %#x.\n", root_parameter->parameter_type);
+            return false;
+    }
+
+    root_descriptor = &root_parameter->u.descriptor;
+
+    vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    vk_descriptor_write->pNext = NULL;
+    vk_descriptor_write->dstSet = vk_descriptor_set;
+    vk_descriptor_write->dstBinding = root_descriptor->binding;
+    vk_descriptor_write->dstArrayElement = 0;
+    vk_descriptor_write->descriptorCount = 1;
+    vk_descriptor_write->pImageInfo = NULL;
+    vk_descriptor_write->pBufferInfo = vk_buffer_info;
+    vk_descriptor_write->pTexelBufferView = vk_buffer_view;
+
+    return true;
+}
+
+static void d3d12_command_list_update_push_descriptors(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+    VkWriteDescriptorSet *descriptor_writes = NULL, *current_descriptor_write;
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    VkDescriptorBufferInfo *buffer_infos = NULL, *current_buffer_info;
+    const struct d3d12_root_parameter *root_parameter;
+    struct vkd3d_push_descriptor *push_descriptor;
+    struct d3d12_device *device = list->device;
+    VkDescriptorBufferInfo *vk_buffer_info;
+    unsigned int i, descriptor_count;
+    VkBufferView *vk_buffer_view;
+
+    if (!bindings->push_descriptor_dirty_mask)
+        return;
+
+    descriptor_count = vkd3d_popcount(bindings->push_descriptor_dirty_mask);
+
+    if (!(descriptor_writes = vkd3d_calloc(descriptor_count, sizeof(*descriptor_writes))))
+        return;
+    if (!(buffer_infos = vkd3d_calloc(descriptor_count, sizeof(*buffer_infos))))
+        goto done;
+
+    descriptor_count = 0;
+    current_buffer_info = buffer_infos;
+    current_descriptor_write = descriptor_writes;
+    for (i = 0; i < ARRAY_SIZE(bindings->push_descriptors); ++i)
+    {
+        if (!(bindings->push_descriptor_dirty_mask & (1u << i)))
+            continue;
+
+        root_parameter = root_signature_get_root_descriptor(root_signature, i);
+        push_descriptor = &bindings->push_descriptors[i];
+
+        if (root_parameter->parameter_type == D3D12_ROOT_PARAMETER_TYPE_CBV)
+        {
+            vk_buffer_view = NULL;
+            vk_buffer_info = current_buffer_info;
+            vk_buffer_info->buffer = push_descriptor->u.cbv.vk_buffer;
+            vk_buffer_info->offset = push_descriptor->u.cbv.offset;
+            vk_buffer_info->range = VK_WHOLE_SIZE;
+        }
+        else
+        {
+            vk_buffer_view = &push_descriptor->u.vk_buffer_view;
+            vk_buffer_info = NULL;
+        }
+
+        if (!vk_write_descriptor_set_from_root_descriptor(current_descriptor_write,
+                root_parameter, bindings->descriptor_set, vk_buffer_view, vk_buffer_info))
+            continue;
+
+        ++descriptor_count;
+        ++current_descriptor_write;
+        ++current_buffer_info;
+    }
+
+    VK_CALL(vkUpdateDescriptorSets(device->vk_device, descriptor_count, descriptor_writes, 0, NULL));
+    bindings->push_descriptor_dirty_mask = 0;
+
+done:
+    vkd3d_free(descriptor_writes);
+    vkd3d_free(buffer_infos);
+}
+
+static void d3d12_command_list_update_uav_counter_descriptors(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct d3d12_pipeline_state *state = list->state;
+    VkDevice vk_device = list->device->vk_device;
+    VkWriteDescriptorSet *vk_descriptor_writes;
+    VkDescriptorSet vk_descriptor_set;
+    unsigned int uav_counter_count;
+    unsigned int i;
+
+    if (!state || !bindings->uav_counters_dirty)
+        return;
+
+    uav_counter_count = state->uav_counter_count;
+    if (!(vk_descriptor_writes = vkd3d_calloc(uav_counter_count, sizeof(*vk_descriptor_writes))))
+        return;
+    if (!(vk_descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator, state->vk_set_layout)))
+        goto done;
+
+    for (i = 0; i < uav_counter_count; ++i)
+    {
+        const struct vkd3d_shader_uav_counter_binding *uav_counter = &state->uav_counters[i];
+        const VkBufferView *vk_uav_counter_views = bindings->vk_uav_counter_views;
+
+        assert(vk_uav_counter_views[i]);
+
+        vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+        vk_descriptor_writes[i].pNext = NULL;
+        vk_descriptor_writes[i].dstSet = vk_descriptor_set;
+        vk_descriptor_writes[i].dstBinding = uav_counter->binding.binding;
+        vk_descriptor_writes[i].dstArrayElement = 0;
+        vk_descriptor_writes[i].descriptorCount = 1;
+        vk_descriptor_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+        vk_descriptor_writes[i].pImageInfo = NULL;
+        vk_descriptor_writes[i].pBufferInfo = NULL;
+        vk_descriptor_writes[i].pTexelBufferView = &vk_uav_counter_views[i];
+    }
+
+    VK_CALL(vkUpdateDescriptorSets(vk_device, uav_counter_count, vk_descriptor_writes, 0, NULL));
+
+    VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point,
+            state->vk_pipeline_layout, state->set_index, 1, &vk_descriptor_set, 0, NULL));
+
+    bindings->uav_counters_dirty = false;
+
+done:
+    vkd3d_free(vk_descriptor_writes);
+}
+
+static void d3d12_command_list_update_descriptors(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct d3d12_root_signature *rs = bindings->root_signature;
+    struct d3d12_desc *base_descriptor;
+    unsigned int i;
+
+    if (!rs || !rs->vk_set_layout)
+        return;
+
+    if (bindings->descriptor_table_dirty_mask || bindings->push_descriptor_dirty_mask)
+        d3d12_command_list_prepare_descriptors(list, bind_point);
+
+    for (i = 0; i < ARRAY_SIZE(bindings->descriptor_tables); ++i)
+    {
+        if (bindings->descriptor_table_dirty_mask & ((uint64_t)1 << i))
+        {
+            if ((base_descriptor = d3d12_desc_from_gpu_handle(bindings->descriptor_tables[i])))
+                d3d12_command_list_update_descriptor_table(list, bind_point, i, base_descriptor);
+            else
+                WARN("Descriptor table %u is not set.\n", i);
+        }
+    }
+    bindings->descriptor_table_dirty_mask = 0;
+
+    d3d12_command_list_update_push_descriptors(list, bind_point);
+
+    if (bindings->descriptor_set)
+    {
+        VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point,
+                rs->vk_pipeline_layout, rs->main_set, 1, &bindings->descriptor_set, 0, NULL));
+        bindings->in_use = true;
+    }
+
+    d3d12_command_list_update_uav_counter_descriptors(list, bind_point);
+}
+
+static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *list)
+{
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (!d3d12_command_list_update_compute_pipeline(list))
+        return false;
+
+    d3d12_command_list_update_descriptors(list, VK_PIPELINE_BIND_POINT_COMPUTE);
+
+    return true;
+}
+
+static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    struct d3d12_graphics_pipeline_state *graphics;
+    struct VkRenderPassBeginInfo begin_desc;
+    VkRenderPass vk_render_pass;
+
+    if (!d3d12_command_list_update_graphics_pipeline(list))
+        return false;
+    if (!d3d12_command_list_update_current_framebuffer(list))
+        return false;
+
+    d3d12_command_list_update_descriptors(list, VK_PIPELINE_BIND_POINT_GRAPHICS);
+
+    if (list->current_render_pass != VK_NULL_HANDLE)
+        return true;
+
+    vk_render_pass = list->pso_render_pass;
+    assert(vk_render_pass);
+
+    begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    begin_desc.pNext = NULL;
+    begin_desc.renderPass = vk_render_pass;
+    begin_desc.framebuffer = list->current_framebuffer;
+    begin_desc.renderArea.offset.x = 0;
+    begin_desc.renderArea.offset.y = 0;
+    d3d12_command_list_get_fb_extent(list,
+            &begin_desc.renderArea.extent.width, &begin_desc.renderArea.extent.height, NULL);
+    begin_desc.clearValueCount = 0;
+    begin_desc.pClearValues = NULL;
+    VK_CALL(vkCmdBeginRenderPass(list->vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE));
+
+    list->current_render_pass = vk_render_pass;
+
+    graphics = &list->state->u.graphics;
+    if (graphics->xfb_enabled)
+    {
+        VK_CALL(vkCmdBeginTransformFeedbackEXT(list->vk_command_buffer, 0, ARRAY_SIZE(list->so_counter_buffers),
+                list->so_counter_buffers, list->so_counter_buffer_offsets));
+
+        list->xfb_enabled = true;
+    }
+
+    return true;
+}
+
+static void d3d12_command_list_check_index_buffer_strip_cut_value(struct d3d12_command_list *list)
+{
+    struct d3d12_graphics_pipeline_state *graphics = &list->state->u.graphics;
+
+    /* In Vulkan, the strip cut value is derived from the index buffer format. */
+    switch (graphics->index_buffer_strip_cut_value)
+    {
+        case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF:
+            if (list->index_buffer_format != DXGI_FORMAT_R16_UINT)
+            {
+                FIXME("Strip cut value 0xffff is not supported with index buffer format %#x.\n",
+                        list->index_buffer_format);
+            }
+            break;
+
+        case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF:
+            if (list->index_buffer_format != DXGI_FORMAT_R32_UINT)
+            {
+                FIXME("Strip cut value 0xffffffff is not supported with index buffer format %#x.\n",
+                        list->index_buffer_format);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_DrawInstanced(ID3D12GraphicsCommandList2 *iface,
+        UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location,
+        UINT start_instance_location)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, vertex_count_per_instance %u, instance_count %u, "
+            "start_vertex_location %u, start_instance_location %u.\n",
+            iface, vertex_count_per_instance, instance_count,
+            start_vertex_location, start_instance_location);
+
+    vk_procs = &list->device->vk_procs;
+
+    if (!d3d12_command_list_begin_render_pass(list))
+    {
+        WARN("Failed to begin render pass, ignoring draw call.\n");
+        return;
+    }
+
+    VK_CALL(vkCmdDraw(list->vk_command_buffer, vertex_count_per_instance,
+            instance_count, start_vertex_location, start_instance_location));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_DrawIndexedInstanced(ID3D12GraphicsCommandList2 *iface,
+        UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location,
+        INT base_vertex_location, UINT start_instance_location)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, index_count_per_instance %u, instance_count %u, start_vertex_location %u, "
+            "base_vertex_location %d, start_instance_location %u.\n",
+            iface, index_count_per_instance, instance_count, start_vertex_location,
+            base_vertex_location, start_instance_location);
+
+    if (!d3d12_command_list_begin_render_pass(list))
+    {
+        WARN("Failed to begin render pass, ignoring draw call.\n");
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    d3d12_command_list_check_index_buffer_strip_cut_value(list);
+
+    VK_CALL(vkCmdDrawIndexed(list->vk_command_buffer, index_count_per_instance,
+            instance_count, start_vertex_location, base_vertex_location, start_instance_location));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(ID3D12GraphicsCommandList2 *iface,
+        UINT x, UINT y, UINT z)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, x %u, y %u, z %u.\n", iface, x, y, z);
+
+    if (!d3d12_command_list_update_compute_state(list))
+    {
+        WARN("Failed to update compute state, ignoring dispatch.\n");
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    VK_CALL(vkCmdDispatch(list->vk_command_buffer, x, y, z));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_CopyBufferRegion(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst, UINT64 dst_offset, ID3D12Resource *src, UINT64 src_offset, UINT64 byte_count)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *dst_resource, *src_resource;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkBufferCopy buffer_copy;
+
+    TRACE("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, "
+            "src_offset %#"PRIx64", byte_count %#"PRIx64".\n",
+            iface, dst, dst_offset, src, src_offset, byte_count);
+
+    vk_procs = &list->device->vk_procs;
+
+    dst_resource = unsafe_impl_from_ID3D12Resource(dst);
+    assert(d3d12_resource_is_buffer(dst_resource));
+    src_resource = unsafe_impl_from_ID3D12Resource(src);
+    assert(d3d12_resource_is_buffer(src_resource));
+
+    d3d12_command_list_track_resource_usage(list, dst_resource);
+    d3d12_command_list_track_resource_usage(list, src_resource);
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    buffer_copy.srcOffset = src_offset;
+    buffer_copy.dstOffset = dst_offset;
+    buffer_copy.size = byte_count;
+
+    VK_CALL(vkCmdCopyBuffer(list->vk_command_buffer,
+            src_resource->u.vk_buffer, dst_resource->u.vk_buffer, 1, &buffer_copy));
+}
+
+static void vk_image_subresource_layers_from_d3d12(VkImageSubresourceLayers *subresource,
+        const struct vkd3d_format *format, unsigned int sub_resource_idx, unsigned int miplevel_count)
+{
+    subresource->aspectMask = format->vk_aspect_mask;
+    subresource->mipLevel = sub_resource_idx % miplevel_count;
+    subresource->baseArrayLayer = sub_resource_idx / miplevel_count;
+    subresource->layerCount = 1;
+}
+
+static void vk_extent_3d_from_d3d12_miplevel(VkExtent3D *extent,
+        const D3D12_RESOURCE_DESC *resource_desc, unsigned int miplevel_idx)
+{
+    extent->width = d3d12_resource_desc_get_width(resource_desc, miplevel_idx);
+    extent->height = d3d12_resource_desc_get_height(resource_desc, miplevel_idx);
+    extent->depth = d3d12_resource_desc_get_depth(resource_desc, miplevel_idx);
+}
+
+static void vk_buffer_image_copy_from_d3d12(VkBufferImageCopy *copy,
+        const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *footprint, unsigned int sub_resource_idx,
+        const D3D12_RESOURCE_DESC *image_desc, const struct vkd3d_format *format,
+        const D3D12_BOX *src_box, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
+{
+    copy->bufferOffset = footprint->Offset;
+    if (src_box)
+    {
+        VkDeviceSize row_count = footprint->Footprint.Height / format->block_height;
+        copy->bufferOffset += vkd3d_format_get_data_offset(format, footprint->Footprint.RowPitch,
+                row_count * footprint->Footprint.RowPitch, src_box->left, src_box->top, src_box->front);
+    }
+    copy->bufferRowLength = footprint->Footprint.RowPitch /
+            (format->byte_count * format->block_byte_count) * format->block_width;
+    copy->bufferImageHeight = footprint->Footprint.Height;
+    vk_image_subresource_layers_from_d3d12(&copy->imageSubresource,
+            format, sub_resource_idx, image_desc->MipLevels);
+    copy->imageOffset.x = dst_x;
+    copy->imageOffset.y = dst_y;
+    copy->imageOffset.z = dst_z;
+
+    vk_extent_3d_from_d3d12_miplevel(&copy->imageExtent, image_desc,
+            copy->imageSubresource.mipLevel);
+    copy->imageExtent.width -= copy->imageOffset.x;
+    copy->imageExtent.height -= copy->imageOffset.y;
+    copy->imageExtent.depth -= copy->imageOffset.z;
+
+    if (src_box)
+    {
+        copy->imageExtent.width = min(copy->imageExtent.width, src_box->right - src_box->left);
+        copy->imageExtent.height = min(copy->imageExtent.height, src_box->bottom - src_box->top);
+        copy->imageExtent.depth = min(copy->imageExtent.depth, src_box->back - src_box->front);
+    }
+    else
+    {
+        copy->imageExtent.width = min(copy->imageExtent.width, footprint->Footprint.Width);
+        copy->imageExtent.height = min(copy->imageExtent.height, footprint->Footprint.Height);
+        copy->imageExtent.depth = min(copy->imageExtent.depth, footprint->Footprint.Depth);
+    }
+}
+
+static void vk_image_buffer_copy_from_d3d12(VkBufferImageCopy *copy,
+        const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *footprint, unsigned int sub_resource_idx,
+        const D3D12_RESOURCE_DESC *image_desc, const struct vkd3d_format *format,
+        const D3D12_BOX *src_box, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
+{
+    VkDeviceSize row_count = footprint->Footprint.Height / format->block_height;
+
+    copy->bufferOffset = footprint->Offset + vkd3d_format_get_data_offset(format,
+            footprint->Footprint.RowPitch, row_count * footprint->Footprint.RowPitch, dst_x, dst_y, dst_z);
+    copy->bufferRowLength = footprint->Footprint.RowPitch /
+            (format->byte_count * format->block_byte_count) * format->block_width;
+    copy->bufferImageHeight = footprint->Footprint.Height;
+    vk_image_subresource_layers_from_d3d12(&copy->imageSubresource,
+            format, sub_resource_idx, image_desc->MipLevels);
+    copy->imageOffset.x = src_box ? src_box->left : 0;
+    copy->imageOffset.y = src_box ? src_box->top : 0;
+    copy->imageOffset.z = src_box ? src_box->front : 0;
+    if (src_box)
+    {
+        copy->imageExtent.width = src_box->right - src_box->left;
+        copy->imageExtent.height = src_box->bottom - src_box->top;
+        copy->imageExtent.depth = src_box->back - src_box->front;
+    }
+    else
+    {
+        unsigned int miplevel = copy->imageSubresource.mipLevel;
+        vk_extent_3d_from_d3d12_miplevel(&copy->imageExtent, image_desc, miplevel);
+    }
+}
+
+static void vk_image_copy_from_d3d12(VkImageCopy *image_copy,
+        unsigned int src_sub_resource_idx, unsigned int dst_sub_resource_idx,
+        const D3D12_RESOURCE_DESC *src_desc, const D3D12_RESOURCE_DESC *dst_desc,
+        const struct vkd3d_format *src_format, const struct vkd3d_format *dst_format,
+        const D3D12_BOX *src_box, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
+{
+    vk_image_subresource_layers_from_d3d12(&image_copy->srcSubresource,
+            src_format, src_sub_resource_idx, src_desc->MipLevels);
+    image_copy->srcOffset.x = src_box ? src_box->left : 0;
+    image_copy->srcOffset.y = src_box ? src_box->top : 0;
+    image_copy->srcOffset.z = src_box ? src_box->front : 0;
+    vk_image_subresource_layers_from_d3d12(&image_copy->dstSubresource,
+            dst_format, dst_sub_resource_idx, dst_desc->MipLevels);
+    image_copy->dstOffset.x = dst_x;
+    image_copy->dstOffset.y = dst_y;
+    image_copy->dstOffset.z = dst_z;
+    if (src_box)
+    {
+        image_copy->extent.width = src_box->right - src_box->left;
+        image_copy->extent.height = src_box->bottom - src_box->top;
+        image_copy->extent.depth = src_box->back - src_box->front;
+    }
+    else
+    {
+        unsigned int miplevel = image_copy->srcSubresource.mipLevel;
+        vk_extent_3d_from_d3d12_miplevel(&image_copy->extent, src_desc, miplevel);
+    }
+}
+
+static HRESULT d3d12_command_list_allocate_transfer_buffer(struct d3d12_command_list *list,
+        VkDeviceSize size, struct vkd3d_buffer *buffer)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    struct d3d12_device *device = list->device;
+    D3D12_HEAP_PROPERTIES heap_properties;
+    D3D12_RESOURCE_DESC buffer_desc;
+    HRESULT hr;
+
+    memset(&heap_properties, 0, sizeof(heap_properties));
+    heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
+
+    buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    buffer_desc.Alignment = 0;
+    buffer_desc.Width = size;
+    buffer_desc.Height = 1;
+    buffer_desc.DepthOrArraySize = 1;
+    buffer_desc.MipLevels = 1;
+    buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
+    buffer_desc.SampleDesc.Count = 1;
+    buffer_desc.SampleDesc.Quality = 0;
+    buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    buffer_desc.Flags = D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+
+    if (FAILED(hr = vkd3d_create_buffer(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
+            &buffer_desc, &buffer->vk_buffer)))
+        return hr;
+    if (FAILED(hr = vkd3d_allocate_buffer_memory(device, buffer->vk_buffer,
+            &heap_properties, D3D12_HEAP_FLAG_NONE, &buffer->vk_memory, NULL, NULL)))
+    {
+        VK_CALL(vkDestroyBuffer(device->vk_device, buffer->vk_buffer, NULL));
+        return hr;
+    }
+
+    if (!d3d12_command_allocator_add_transfer_buffer(list->allocator, buffer))
+    {
+        ERR("Failed to add transfer buffer.\n");
+        vkd3d_buffer_destroy(buffer, device);
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+/* In Vulkan, each depth/stencil format is only compatible with itself.
+ * This means that we are not allowed to copy texture regions directly between
+ * depth/stencil and color formats.
+ *
+ * FIXME: Implement color <-> depth/stencil blits in shaders.
+ */
+static void d3d12_command_list_copy_incompatible_texture_region(struct d3d12_command_list *list,
+        struct d3d12_resource *dst_resource, unsigned int dst_sub_resource_idx,
+        const struct vkd3d_format *dst_format, struct d3d12_resource *src_resource,
+        unsigned int src_sub_resource_idx, const struct vkd3d_format *src_format)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const D3D12_RESOURCE_DESC *dst_desc = &dst_resource->desc;
+    const D3D12_RESOURCE_DESC *src_desc = &src_resource->desc;
+    unsigned int dst_miplevel_idx, src_miplevel_idx;
+    struct vkd3d_buffer transfer_buffer;
+    VkBufferImageCopy buffer_image_copy;
+    VkBufferMemoryBarrier vk_barrier;
+    VkDeviceSize buffer_size;
+    HRESULT hr;
+
+    WARN("Copying incompatible texture formats %#x, %#x -> %#x, %#x.\n",
+            src_format->dxgi_format, src_format->vk_format,
+            dst_format->dxgi_format, dst_format->vk_format);
+
+    assert(d3d12_resource_is_texture(dst_resource));
+    assert(d3d12_resource_is_texture(src_resource));
+    assert(!vkd3d_format_is_compressed(dst_format));
+    assert(!vkd3d_format_is_compressed(src_format));
+    assert(dst_format->byte_count == src_format->byte_count);
+
+    buffer_image_copy.bufferOffset = 0;
+    buffer_image_copy.bufferRowLength = 0;
+    buffer_image_copy.bufferImageHeight = 0;
+    vk_image_subresource_layers_from_d3d12(&buffer_image_copy.imageSubresource,
+            src_format, src_sub_resource_idx, src_desc->MipLevels);
+    src_miplevel_idx = buffer_image_copy.imageSubresource.mipLevel;
+    buffer_image_copy.imageOffset.x = 0;
+    buffer_image_copy.imageOffset.y = 0;
+    buffer_image_copy.imageOffset.z = 0;
+    vk_extent_3d_from_d3d12_miplevel(&buffer_image_copy.imageExtent, src_desc, src_miplevel_idx);
+
+    buffer_size = src_format->byte_count * buffer_image_copy.imageExtent.width *
+            buffer_image_copy.imageExtent.height * buffer_image_copy.imageExtent.depth;
+    if (FAILED(hr = d3d12_command_list_allocate_transfer_buffer(list, buffer_size, &transfer_buffer)))
+    {
+        ERR("Failed to allocate transfer buffer, hr %#x.\n", hr);
+        return;
+    }
+
+    VK_CALL(vkCmdCopyImageToBuffer(list->vk_command_buffer,
+            src_resource->u.vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+            transfer_buffer.vk_buffer, 1, &buffer_image_copy));
+
+    vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+    vk_barrier.pNext = NULL;
+    vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+    vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+    vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    vk_barrier.buffer = transfer_buffer.vk_buffer;
+    vk_barrier.offset = 0;
+    vk_barrier.size = VK_WHOLE_SIZE;
+    VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,
+            VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+            0, NULL, 1, &vk_barrier, 0, NULL));
+
+    vk_image_subresource_layers_from_d3d12(&buffer_image_copy.imageSubresource,
+            dst_format, dst_sub_resource_idx, dst_desc->MipLevels);
+    dst_miplevel_idx = buffer_image_copy.imageSubresource.mipLevel;
+
+    assert(d3d12_resource_desc_get_width(src_desc, src_miplevel_idx) ==
+            d3d12_resource_desc_get_width(dst_desc, dst_miplevel_idx));
+    assert(d3d12_resource_desc_get_height(src_desc, src_miplevel_idx) ==
+            d3d12_resource_desc_get_height(dst_desc, dst_miplevel_idx));
+    assert(d3d12_resource_desc_get_depth(src_desc, src_miplevel_idx) ==
+            d3d12_resource_desc_get_depth(dst_desc, dst_miplevel_idx));
+
+    VK_CALL(vkCmdCopyBufferToImage(list->vk_command_buffer,
+            transfer_buffer.vk_buffer, dst_resource->u.vk_image,
+            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy));
+}
+
+static bool validate_d3d12_box(const D3D12_BOX *box)
+{
+    return box->right > box->left
+            && box->bottom > box->top
+            && box->back > box->front;
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(ID3D12GraphicsCommandList2 *iface,
+        const D3D12_TEXTURE_COPY_LOCATION *dst, UINT dst_x, UINT dst_y, UINT dst_z,
+        const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *dst_resource, *src_resource;
+    const struct vkd3d_format *src_format, *dst_format;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkBufferImageCopy buffer_image_copy;
+    VkImageCopy image_copy;
+
+    TRACE("iface %p, dst %p, dst_x %u, dst_y %u, dst_z %u, src %p, src_box %p.\n",
+            iface, dst, dst_x, dst_y, dst_z, src, src_box);
+
+    if (src_box && !validate_d3d12_box(src_box))
+    {
+        WARN("Empty box %s.\n", debug_d3d12_box(src_box));
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    dst_resource = unsafe_impl_from_ID3D12Resource(dst->pResource);
+    src_resource = unsafe_impl_from_ID3D12Resource(src->pResource);
+
+    d3d12_command_list_track_resource_usage(list, dst_resource);
+    d3d12_command_list_track_resource_usage(list, src_resource);
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (src->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX
+            && dst->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT)
+    {
+        assert(d3d12_resource_is_buffer(dst_resource));
+        assert(d3d12_resource_is_texture(src_resource));
+
+        if (!(dst_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &src_resource->desc, dst->u.PlacedFootprint.Footprint.Format)))
+        {
+            WARN("Invalid format %#x.\n", dst->u.PlacedFootprint.Footprint.Format);
+            return;
+        }
+
+        if (dst_format->is_emulated)
+        {
+            FIXME("Format %#x is not supported yet.\n", dst_format->dxgi_format);
+            return;
+        }
+
+        if ((dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT)
+                && (dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT))
+            FIXME("Depth-stencil format %#x not fully supported yet.\n", dst_format->dxgi_format);
+
+        vk_image_buffer_copy_from_d3d12(&buffer_image_copy, &dst->u.PlacedFootprint,
+                src->u.SubresourceIndex, &src_resource->desc, dst_format, src_box, dst_x, dst_y, dst_z);
+        VK_CALL(vkCmdCopyImageToBuffer(list->vk_command_buffer,
+                src_resource->u.vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                dst_resource->u.vk_buffer, 1, &buffer_image_copy));
+    }
+    else if (src->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT
+            && dst->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX)
+    {
+        assert(d3d12_resource_is_texture(dst_resource));
+        assert(d3d12_resource_is_buffer(src_resource));
+
+        if (!(src_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &dst_resource->desc, src->u.PlacedFootprint.Footprint.Format)))
+        {
+            WARN("Invalid format %#x.\n", src->u.PlacedFootprint.Footprint.Format);
+            return;
+        }
+
+        if (src_format->is_emulated)
+        {
+            FIXME("Format %#x is not supported yet.\n", src_format->dxgi_format);
+            return;
+        }
+
+        if ((src_format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT)
+                && (src_format->vk_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT))
+            FIXME("Depth-stencil format %#x not fully supported yet.\n", src_format->dxgi_format);
+
+        vk_buffer_image_copy_from_d3d12(&buffer_image_copy, &src->u.PlacedFootprint,
+                dst->u.SubresourceIndex, &dst_resource->desc, src_format, src_box, dst_x, dst_y, dst_z);
+        VK_CALL(vkCmdCopyBufferToImage(list->vk_command_buffer,
+                src_resource->u.vk_buffer, dst_resource->u.vk_image,
+                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy));
+    }
+    else if (src->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX
+            && dst->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX)
+    {
+        assert(d3d12_resource_is_texture(dst_resource));
+        assert(d3d12_resource_is_texture(src_resource));
+
+        if (!(dst_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &dst_resource->desc, DXGI_FORMAT_UNKNOWN)))
+        {
+            WARN("Invalid format %#x.\n", dst_resource->desc.Format);
+            return;
+        }
+        if (!(src_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &src_resource->desc, DXGI_FORMAT_UNKNOWN)))
+        {
+            WARN("Invalid format %#x.\n", src_resource->desc.Format);
+            return;
+        }
+
+        if ((dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT)
+                && (dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT))
+            FIXME("Depth-stencil format %#x not fully supported yet.\n", dst_format->dxgi_format);
+        if ((src_format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT)
+                && (src_format->vk_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT))
+            FIXME("Depth-stencil format %#x not fully supported yet.\n", src_format->dxgi_format);
+
+        if (dst_format->vk_aspect_mask != src_format->vk_aspect_mask)
+        {
+            d3d12_command_list_copy_incompatible_texture_region(list,
+                    dst_resource, dst->u.SubresourceIndex, dst_format,
+                    src_resource, src->u.SubresourceIndex, src_format);
+            return;
+        }
+
+        vk_image_copy_from_d3d12(&image_copy, src->u.SubresourceIndex, dst->u.SubresourceIndex,
+                 &src_resource->desc, &dst_resource->desc, src_format, dst_format,
+                 src_box, dst_x, dst_y, dst_z);
+        VK_CALL(vkCmdCopyImage(list->vk_command_buffer, src_resource->u.vk_image,
+                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_resource->u.vk_image,
+                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy));
+    }
+    else
+    {
+        FIXME("Copy type %#x -> %#x not implemented.\n", src->Type, dst->Type);
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst, ID3D12Resource *src)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *dst_resource, *src_resource;
+    const struct vkd3d_format *src_format, *dst_format;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkBufferCopy vk_buffer_copy;
+    VkImageCopy vk_image_copy;
+    unsigned int layer_count;
+    unsigned int i;
+
+    TRACE("iface %p, dst_resource %p, src_resource %p.\n", iface, dst, src);
+
+    vk_procs = &list->device->vk_procs;
+
+    dst_resource = unsafe_impl_from_ID3D12Resource(dst);
+    src_resource = unsafe_impl_from_ID3D12Resource(src);
+
+    d3d12_command_list_track_resource_usage(list, dst_resource);
+    d3d12_command_list_track_resource_usage(list, src_resource);
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (d3d12_resource_is_buffer(dst_resource))
+    {
+        assert(d3d12_resource_is_buffer(src_resource));
+        assert(src_resource->desc.Width == dst_resource->desc.Width);
+
+        vk_buffer_copy.srcOffset = 0;
+        vk_buffer_copy.dstOffset = 0;
+        vk_buffer_copy.size = dst_resource->desc.Width;
+        VK_CALL(vkCmdCopyBuffer(list->vk_command_buffer,
+                src_resource->u.vk_buffer, dst_resource->u.vk_buffer, 1, &vk_buffer_copy));
+    }
+    else
+    {
+        if (!(dst_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &dst_resource->desc, DXGI_FORMAT_UNKNOWN)))
+        {
+            WARN("Invalid format %#x.\n", dst_resource->desc.Format);
+            return;
+        }
+        if (!(src_format = vkd3d_format_from_d3d12_resource_desc(list->device,
+                &src_resource->desc, DXGI_FORMAT_UNKNOWN)))
+        {
+            WARN("Invalid format %#x.\n", src_resource->desc.Format);
+            return;
+        }
+
+        layer_count = d3d12_resource_desc_get_layer_count(&dst_resource->desc);
+
+        assert(d3d12_resource_is_texture(dst_resource));
+        assert(d3d12_resource_is_texture(src_resource));
+        assert(dst_resource->desc.MipLevels == src_resource->desc.MipLevels);
+        assert(layer_count == d3d12_resource_desc_get_layer_count(&src_resource->desc));
+
+        for (i = 0; i < dst_resource->desc.MipLevels; ++i)
+        {
+            vk_image_copy_from_d3d12(&vk_image_copy, i, i,
+                    &src_resource->desc, &dst_resource->desc, src_format, dst_format, NULL, 0, 0, 0);
+            vk_image_copy.dstSubresource.layerCount = layer_count;
+            vk_image_copy.srcSubresource.layerCount = layer_count;
+            VK_CALL(vkCmdCopyImage(list->vk_command_buffer, src_resource->u.vk_image,
+                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_resource->u.vk_image,
+                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vk_image_copy));
+        }
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset,
+        D3D12_TILE_COPY_FLAGS flags)
+{
+    FIXME("iface %p, tiled_resource %p, tile_region_start_coordinate %p, tile_region_size %p, "
+            "buffer %p, buffer_offset %#"PRIx64", flags %#x stub!\n",
+            iface, tiled_resource, tile_region_start_coordinate, tile_region_size,
+            buffer, buffer_offset, flags);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresource(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst, UINT dst_sub_resource_idx,
+        ID3D12Resource *src, UINT src_sub_resource_idx, DXGI_FORMAT format)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_format *src_format, *dst_format, *vk_format;
+    struct d3d12_resource *dst_resource, *src_resource;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    const struct d3d12_device *device;
+    VkImageResolve vk_image_resolve;
+
+    TRACE("iface %p, dst_resource %p, dst_sub_resource_idx %u, src_resource %p, src_sub_resource_idx %u, "
+            "format %#x.\n", iface, dst, dst_sub_resource_idx, src, src_sub_resource_idx, format);
+
+    device = list->device;
+    vk_procs = &device->vk_procs;
+
+    dst_resource = unsafe_impl_from_ID3D12Resource(dst);
+    src_resource = unsafe_impl_from_ID3D12Resource(src);
+
+    assert(d3d12_resource_is_texture(dst_resource));
+    assert(d3d12_resource_is_texture(src_resource));
+
+    d3d12_command_list_track_resource_usage(list, dst_resource);
+    d3d12_command_list_track_resource_usage(list, src_resource);
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (!(dst_format = vkd3d_format_from_d3d12_resource_desc(device, &dst_resource->desc, DXGI_FORMAT_UNKNOWN)))
+    {
+        WARN("Invalid format %#x.\n", dst_resource->desc.Format);
+        return;
+    }
+    if (!(src_format = vkd3d_format_from_d3d12_resource_desc(device, &src_resource->desc, DXGI_FORMAT_UNKNOWN)))
+    {
+        WARN("Invalid format %#x.\n", src_resource->desc.Format);
+        return;
+    }
+
+    if (dst_format->type == VKD3D_FORMAT_TYPE_TYPELESS || src_format->type == VKD3D_FORMAT_TYPE_TYPELESS)
+    {
+        if (!(vk_format = vkd3d_format_from_d3d12_resource_desc(device, &dst_resource->desc, format)))
+        {
+            WARN("Invalid format %#x.\n", format);
+            return;
+        }
+        if (dst_format->vk_format != src_format->vk_format || dst_format->vk_format != vk_format->vk_format)
+        {
+            FIXME("Not implemented for typeless resources.\n");
+            return;
+        }
+    }
+
+    /* Resolve of depth/stencil images is not supported in Vulkan. */
+    if ((dst_format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
+            || (src_format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))
+    {
+        FIXME("Resolve of depth/stencil images is not implemented yet.\n");
+        return;
+    }
+
+    vk_image_subresource_layers_from_d3d12(&vk_image_resolve.srcSubresource,
+            src_format, src_sub_resource_idx, src_resource->desc.MipLevels);
+    memset(&vk_image_resolve.srcOffset, 0, sizeof(vk_image_resolve.srcOffset));
+    vk_image_subresource_layers_from_d3d12(&vk_image_resolve.dstSubresource,
+            dst_format, dst_sub_resource_idx, dst_resource->desc.MipLevels);
+    memset(&vk_image_resolve.dstOffset, 0, sizeof(vk_image_resolve.dstOffset));
+    vk_extent_3d_from_d3d12_miplevel(&vk_image_resolve.extent,
+            &dst_resource->desc, vk_image_resolve.dstSubresource.mipLevel);
+
+    VK_CALL(vkCmdResolveImage(list->vk_command_buffer, src_resource->u.vk_image,
+            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_resource->u.vk_image,
+            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vk_image_resolve));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_IASetPrimitiveTopology(ID3D12GraphicsCommandList2 *iface,
+        D3D12_PRIMITIVE_TOPOLOGY topology)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, topology %#x.\n", iface, topology);
+
+    if (topology == D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)
+    {
+        WARN("Ignoring D3D_PRIMITIVE_TOPOLOGY_UNDEFINED.\n");
+        return;
+    }
+
+    if (list->primitive_topology == topology)
+        return;
+
+    list->primitive_topology = topology;
+    d3d12_command_list_invalidate_current_pipeline(list);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_RSSetViewports(ID3D12GraphicsCommandList2 *iface,
+        UINT viewport_count, const D3D12_VIEWPORT *viewports)
+{
+    VkViewport vk_viewports[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    unsigned int i;
+
+    TRACE("iface %p, viewport_count %u, viewports %p.\n", iface, viewport_count, viewports);
+
+    if (viewport_count > ARRAY_SIZE(vk_viewports))
+    {
+        FIXME("Viewport count %u > D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE.\n", viewport_count);
+        viewport_count = ARRAY_SIZE(vk_viewports);
+    }
+
+    for (i = 0; i < viewport_count; ++i)
+    {
+        vk_viewports[i].x = viewports[i].TopLeftX;
+        vk_viewports[i].y = viewports[i].TopLeftY + viewports[i].Height;
+        vk_viewports[i].width = viewports[i].Width;
+        vk_viewports[i].height = -viewports[i].Height;
+        vk_viewports[i].minDepth = viewports[i].MinDepth;
+        vk_viewports[i].maxDepth = viewports[i].MaxDepth;
+
+        if (!vk_viewports[i].width || !vk_viewports[i].height)
+        {
+            FIXME_ONCE("Invalid viewport %u, ignoring RSSetViewports().\n", i);
+            return;
+        }
+    }
+
+    vk_procs = &list->device->vk_procs;
+    VK_CALL(vkCmdSetViewport(list->vk_command_buffer, 0, viewport_count, vk_viewports));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_RSSetScissorRects(ID3D12GraphicsCommandList2 *iface,
+        UINT rect_count, const D3D12_RECT *rects)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    VkRect2D vk_rects[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+    const struct vkd3d_vk_device_procs *vk_procs;
+    unsigned int i;
+
+    TRACE("iface %p, rect_count %u, rects %p.\n", iface, rect_count, rects);
+
+    if (rect_count > ARRAY_SIZE(vk_rects))
+    {
+        FIXME("Rect count %u > D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE.\n", rect_count);
+        rect_count = ARRAY_SIZE(vk_rects);
+    }
+
+    for (i = 0; i < rect_count; ++i)
+    {
+        vk_rects[i].offset.x = rects[i].left;
+        vk_rects[i].offset.y = rects[i].top;
+        vk_rects[i].extent.width = rects[i].right - rects[i].left;
+        vk_rects[i].extent.height = rects[i].bottom - rects[i].top;
+    }
+
+    vk_procs = &list->device->vk_procs;
+    VK_CALL(vkCmdSetScissor(list->vk_command_buffer, 0, rect_count, vk_rects));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_OMSetBlendFactor(ID3D12GraphicsCommandList2 *iface,
+        const FLOAT blend_factor[4])
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, blend_factor %p.\n", iface, blend_factor);
+
+    vk_procs = &list->device->vk_procs;
+    VK_CALL(vkCmdSetBlendConstants(list->vk_command_buffer, blend_factor));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_OMSetStencilRef(ID3D12GraphicsCommandList2 *iface,
+        UINT stencil_ref)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, stencil_ref %u.\n", iface, stencil_ref);
+
+    vk_procs = &list->device->vk_procs;
+    VK_CALL(vkCmdSetStencilReference(list->vk_command_buffer, VK_STENCIL_FRONT_AND_BACK, stencil_ref));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(ID3D12GraphicsCommandList2 *iface,
+        ID3D12PipelineState *pipeline_state)
+{
+    struct d3d12_pipeline_state *state = unsafe_impl_from_ID3D12PipelineState(pipeline_state);
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, pipeline_state %p.\n", iface, pipeline_state);
+
+    if (list->state == state)
+        return;
+
+    d3d12_command_list_invalidate_bindings(list, state);
+    d3d12_command_list_invalidate_current_pipeline(list);
+
+    list->state = state;
+}
+
+static bool is_ds_multiplanar_resolvable(unsigned int first_state, unsigned int second_state)
+{
+    /* Only combinations of depth/stencil read/write are supported. */
+    return first_state == second_state
+            || ((first_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE))
+            && (second_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE)));
+}
+
+static unsigned int d3d12_find_ds_multiplanar_transition(const D3D12_RESOURCE_BARRIER *barriers,
+        unsigned int i, unsigned int barrier_count, unsigned int sub_resource_count)
+{
+    unsigned int sub_resource_idx = barriers[i].u.Transition.Subresource;
+    unsigned int j;
+
+    for (j = i + 1; j < barrier_count; ++j)
+    {
+        if (barriers[j].Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION
+                && barriers[j].u.Transition.pResource == barriers[i].u.Transition.pResource
+                && sub_resource_idx % sub_resource_count == barriers[j].u.Transition.Subresource % sub_resource_count)
+        {
+            /* Second barrier must be for a different plane. */
+            if (barriers[j].u.Transition.Subresource == sub_resource_idx)
+                return 0;
+
+            /* Validate the second barrier and check if the combination of two states is supported. */
+            if (!is_valid_resource_state(barriers[j].u.Transition.StateBefore)
+                    || !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateBefore, barriers[j].u.Transition.StateBefore)
+                    || !is_valid_resource_state(barriers[j].u.Transition.StateAfter)
+                    || !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateAfter, barriers[j].u.Transition.StateAfter)
+                    || barriers[j].u.Transition.Subresource >= sub_resource_count * 2u)
+                return 0;
+
+            return j;
+        }
+    }
+    return 0;
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList2 *iface,
+        UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    bool have_aliasing_barriers = false, have_split_barriers = false;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    const struct vkd3d_vulkan_info *vk_info;
+    bool *multiplanar_handled = NULL;
+    unsigned int i;
+
+    TRACE("iface %p, barrier_count %u, barriers %p.\n", iface, barrier_count, barriers);
+
+    vk_procs = &list->device->vk_procs;
+    vk_info = &list->device->vk_info;
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    for (i = 0; i < barrier_count; ++i)
+    {
+        unsigned int sub_resource_idx = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+        VkPipelineStageFlags src_stage_mask = 0, dst_stage_mask = 0;
+        VkAccessFlags src_access_mask = 0, dst_access_mask = 0;
+        const D3D12_RESOURCE_BARRIER *current = &barriers[i];
+        VkImageLayout layout_before, layout_after;
+        struct d3d12_resource *resource;
+
+        have_split_barriers = have_split_barriers
+                || (current->Flags & D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY)
+                || (current->Flags & D3D12_RESOURCE_BARRIER_FLAG_END_ONLY);
+
+        if (current->Flags & D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY)
+            continue;
+
+        switch (current->Type)
+        {
+            case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION:
+            {
+                unsigned int state_before, state_after, stencil_state_before = 0, stencil_state_after = 0;
+                const D3D12_RESOURCE_TRANSITION_BARRIER *transition = &current->u.Transition;
+
+                if (!is_valid_resource_state(transition->StateBefore))
+                {
+                    d3d12_command_list_mark_as_invalid(list,
+                            "Invalid StateBefore %#x (barrier %u).", transition->StateBefore, i);
+                    continue;
+                }
+                if (!is_valid_resource_state(transition->StateAfter))
+                {
+                    d3d12_command_list_mark_as_invalid(list,
+                            "Invalid StateAfter %#x (barrier %u).", transition->StateAfter, i);
+                    continue;
+                }
+
+                if (!(resource = unsafe_impl_from_ID3D12Resource(transition->pResource)))
+                {
+                    d3d12_command_list_mark_as_invalid(list, "A resource pointer is NULL.");
+                    continue;
+                }
+
+                if (multiplanar_handled && multiplanar_handled[i])
+                    continue;
+
+                state_before = transition->StateBefore;
+                state_after = transition->StateAfter;
+
+                sub_resource_idx = transition->Subresource;
+
+                if (sub_resource_idx != D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
+                        && (resource->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
+                {
+                    unsigned int sub_resource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
+                    unsigned int j = d3d12_find_ds_multiplanar_transition(barriers, i, barrier_count, sub_resource_count);
+                    if (j && (multiplanar_handled || (multiplanar_handled = vkd3d_calloc(barrier_count, sizeof(*multiplanar_handled)))))
+                    {
+                        multiplanar_handled[j] = true;
+                        if (sub_resource_idx >= sub_resource_count)
+                        {
+                            sub_resource_idx -= sub_resource_count;
+                            /* The stencil barrier is at i, depth at j. */
+                            state_before = barriers[j].u.Transition.StateBefore;
+                            state_after = barriers[j].u.Transition.StateAfter;
+                            stencil_state_before = transition->StateBefore;
+                            stencil_state_after = transition->StateAfter;
+                        }
+                        else
+                        {
+                            /* Depth at i, stencil at j. */
+                            stencil_state_before = barriers[j].u.Transition.StateBefore;
+                            stencil_state_after = barriers[j].u.Transition.StateAfter;
+                        }
+                    }
+                    else if (sub_resource_idx >= sub_resource_count)
+                    {
+                        FIXME_ONCE("Unhandled sub-resource idx %u.\n", sub_resource_idx);
+                        continue;
+                    }
+                }
+
+                if (!vk_barrier_parameters_from_d3d12_resource_state(state_before, stencil_state_before,
+                        resource, list->vk_queue_flags, vk_info, &src_access_mask, &src_stage_mask, &layout_before))
+                {
+                    FIXME("Unhandled state %#x.\n", state_before);
+                    continue;
+                }
+                if (!vk_barrier_parameters_from_d3d12_resource_state(state_after, stencil_state_after,
+                        resource, list->vk_queue_flags, vk_info, &dst_access_mask, &dst_stage_mask, &layout_after))
+                {
+                    FIXME("Unhandled state %#x.\n", state_after);
+                    continue;
+                }
+
+                TRACE("Transition barrier (resource %p, subresource %#x, before %#x, after %#x).\n",
+                        resource, transition->Subresource, transition->StateBefore, transition->StateAfter);
+                break;
+            }
+
+            case D3D12_RESOURCE_BARRIER_TYPE_UAV:
+            {
+                const D3D12_RESOURCE_UAV_BARRIER *uav = &current->u.UAV;
+                VkPipelineStageFlags stage_mask;
+                VkImageLayout image_layout;
+                VkAccessFlags access_mask;
+
+                resource = unsafe_impl_from_ID3D12Resource(uav->pResource);
+                vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0,
+                        resource, list->vk_queue_flags, vk_info, &access_mask, &stage_mask, &image_layout);
+                src_access_mask = dst_access_mask = access_mask;
+                src_stage_mask = dst_stage_mask = stage_mask;
+                layout_before = layout_after = image_layout;
+
+                TRACE("UAV barrier (resource %p).\n", resource);
+                break;
+            }
+
+            case D3D12_RESOURCE_BARRIER_TYPE_ALIASING:
+                have_aliasing_barriers = true;
+                continue;
+            default:
+                WARN("Invalid barrier type %#x.\n", current->Type);
+                continue;
+        }
+
+        if (resource)
+            d3d12_command_list_track_resource_usage(list, resource);
+
+        if (!resource)
+        {
+            VkMemoryBarrier vk_barrier;
+
+            vk_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+            vk_barrier.pNext = NULL;
+            vk_barrier.srcAccessMask = src_access_mask;
+            vk_barrier.dstAccessMask = dst_access_mask;
+
+            VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, src_stage_mask, dst_stage_mask, 0,
+                    1, &vk_barrier, 0, NULL, 0, NULL));
+        }
+        else if (d3d12_resource_is_buffer(resource))
+        {
+            VkBufferMemoryBarrier vk_barrier;
+
+            vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+            vk_barrier.pNext = NULL;
+            vk_barrier.srcAccessMask = src_access_mask;
+            vk_barrier.dstAccessMask = dst_access_mask;
+            vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+            vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+            vk_barrier.buffer = resource->u.vk_buffer;
+            vk_barrier.offset = 0;
+            vk_barrier.size = VK_WHOLE_SIZE;
+
+            VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, src_stage_mask, dst_stage_mask, 0,
+                    0, NULL, 1, &vk_barrier, 0, NULL));
+        }
+        else
+        {
+            const struct vkd3d_format *format;
+            VkImageMemoryBarrier vk_barrier;
+
+            if (!(format = vkd3d_format_from_d3d12_resource_desc(list->device, &resource->desc, 0)))
+            {
+                ERR("Resource %p has invalid format %#x.\n", resource, resource->desc.Format);
+                continue;
+            }
+
+            vk_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+            vk_barrier.pNext = NULL;
+            vk_barrier.srcAccessMask = src_access_mask;
+            vk_barrier.dstAccessMask = dst_access_mask;
+            vk_barrier.oldLayout = layout_before;
+            vk_barrier.newLayout = layout_after;
+            vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+            vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+            vk_barrier.image = resource->u.vk_image;
+
+            vk_barrier.subresourceRange.aspectMask = format->vk_aspect_mask;
+            if (sub_resource_idx == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)
+            {
+                vk_barrier.subresourceRange.baseMipLevel = 0;
+                vk_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+                vk_barrier.subresourceRange.baseArrayLayer = 0;
+                vk_barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+            }
+            else
+            {
+                /* FIXME: Some formats in D3D12 are planar. Each plane is a separate sub-resource. */
+                if (sub_resource_idx >= d3d12_resource_desc_get_sub_resource_count(&resource->desc))
+                {
+                    FIXME_ONCE("Unhandled sub-resource idx %u.\n", sub_resource_idx);
+                    continue;
+                }
+
+                vk_barrier.subresourceRange.baseMipLevel = sub_resource_idx % resource->desc.MipLevels;
+                vk_barrier.subresourceRange.levelCount = 1;
+                vk_barrier.subresourceRange.baseArrayLayer = sub_resource_idx / resource->desc.MipLevels;
+                vk_barrier.subresourceRange.layerCount = 1;
+            }
+
+            VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, src_stage_mask, dst_stage_mask, 0,
+                    0, NULL, 0, NULL, 1, &vk_barrier));
+        }
+    }
+
+    vkd3d_free(multiplanar_handled);
+
+    if (have_aliasing_barriers)
+        FIXME_ONCE("Aliasing barriers not implemented yet.\n");
+
+    /* Vulkan doesn't support split barriers. */
+    if (have_split_barriers)
+        WARN("Issuing split barrier(s) on D3D12_RESOURCE_BARRIER_FLAG_END_ONLY.\n");
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ExecuteBundle(ID3D12GraphicsCommandList2 *iface,
+        ID3D12GraphicsCommandList *command_list)
+{
+    FIXME("iface %p, command_list %p stub!\n", iface, command_list);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetDescriptorHeaps(ID3D12GraphicsCommandList2 *iface,
+        UINT heap_count, ID3D12DescriptorHeap *const *heaps)
+{
+    TRACE("iface %p, heap_count %u, heaps %p.\n", iface, heap_count, heaps);
+
+    /* Our current implementation does not need this method.
+     *
+     * It could be used to validate descriptor tables but we do not have an
+     * equivalent of the D3D12 Debug Layer. */
+}
+
+static void d3d12_command_list_set_root_signature(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, const struct d3d12_root_signature *root_signature)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+
+    if (bindings->root_signature == root_signature)
+        return;
+
+    bindings->root_signature = root_signature;
+
+    d3d12_command_list_invalidate_root_parameters(list, bind_point);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootSignature(ID3D12GraphicsCommandList2 *iface,
+        ID3D12RootSignature *root_signature)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_signature %p.\n", iface, root_signature);
+
+    d3d12_command_list_set_root_signature(list, VK_PIPELINE_BIND_POINT_COMPUTE,
+            unsafe_impl_from_ID3D12RootSignature(root_signature));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootSignature(ID3D12GraphicsCommandList2 *iface,
+        ID3D12RootSignature *root_signature)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_signature %p.\n", iface, root_signature);
+
+    d3d12_command_list_set_root_signature(list, VK_PIPELINE_BIND_POINT_GRAPHICS,
+            unsafe_impl_from_ID3D12RootSignature(root_signature));
+}
+
+static void d3d12_command_list_set_descriptor_table(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, unsigned int index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+
+    assert(root_signature_get_descriptor_table(root_signature, index));
+
+    assert(index < ARRAY_SIZE(bindings->descriptor_tables));
+    bindings->descriptor_tables[index] = base_descriptor;
+    bindings->descriptor_table_dirty_mask |= (uint64_t)1 << index;
+    bindings->descriptor_table_active_mask |= (uint64_t)1 << index;
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n",
+            iface, root_parameter_index, base_descriptor.ptr);
+
+    d3d12_command_list_set_descriptor_table(list, VK_PIPELINE_BIND_POINT_COMPUTE,
+            root_parameter_index, base_descriptor);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n",
+            iface, root_parameter_index, base_descriptor.ptr);
+
+    d3d12_command_list_set_descriptor_table(list, VK_PIPELINE_BIND_POINT_GRAPHICS,
+            root_parameter_index, base_descriptor);
+}
+
+static void d3d12_command_list_set_root_constants(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, unsigned int index, unsigned int offset,
+        unsigned int count, const void *data)
+{
+    const struct d3d12_root_signature *root_signature = list->pipeline_bindings[bind_point].root_signature;
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct d3d12_root_constant *c;
+
+    c = root_signature_get_32bit_constants(root_signature, index);
+    VK_CALL(vkCmdPushConstants(list->vk_command_buffer, root_signature->vk_pipeline_layout,
+            c->stage_flags, c->offset + offset * sizeof(uint32_t), count * sizeof(uint32_t), data));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, UINT data, UINT dst_offset)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u.\n",
+            iface, root_parameter_index, data, dst_offset);
+
+    d3d12_command_list_set_root_constants(list, VK_PIPELINE_BIND_POINT_COMPUTE,
+            root_parameter_index, dst_offset, 1, &data);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, UINT data, UINT dst_offset)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u.\n",
+            iface, root_parameter_index, data, dst_offset);
+
+    d3d12_command_list_set_root_constants(list, VK_PIPELINE_BIND_POINT_GRAPHICS,
+            root_parameter_index, dst_offset, 1, &data);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u.\n",
+            iface, root_parameter_index, constant_count, data, dst_offset);
+
+    d3d12_command_list_set_root_constants(list, VK_PIPELINE_BIND_POINT_COMPUTE,
+            root_parameter_index, dst_offset, constant_count, data);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList2 *iface,
+        UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u.\n",
+            iface, root_parameter_index, constant_count, data, dst_offset);
+
+    d3d12_command_list_set_root_constants(list, VK_PIPELINE_BIND_POINT_GRAPHICS,
+            root_parameter_index, dst_offset, constant_count, data);
+}
+
+static void d3d12_command_list_set_root_cbv(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, unsigned int index, D3D12_GPU_VIRTUAL_ADDRESS gpu_address)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info;
+    const struct d3d12_root_parameter *root_parameter;
+    struct VkWriteDescriptorSet descriptor_write;
+    struct VkDescriptorBufferInfo buffer_info;
+    struct d3d12_resource *resource;
+
+    root_parameter = root_signature_get_root_descriptor(root_signature, index);
+    assert(root_parameter->parameter_type == D3D12_ROOT_PARAMETER_TYPE_CBV);
+
+    resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, gpu_address);
+    buffer_info.buffer = resource->u.vk_buffer;
+    buffer_info.offset = gpu_address - resource->gpu_address;
+    buffer_info.range = resource->desc.Width - buffer_info.offset;
+    buffer_info.range = min(buffer_info.range, vk_info->device_limits.maxUniformBufferRange);
+
+    if (vk_info->KHR_push_descriptor)
+    {
+        vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
+                root_parameter, VK_NULL_HANDLE, NULL, &buffer_info);
+        VK_CALL(vkCmdPushDescriptorSetKHR(list->vk_command_buffer, bindings->vk_bind_point,
+                root_signature->vk_pipeline_layout, 0, 1, &descriptor_write));
+    }
+    else
+    {
+        d3d12_command_list_prepare_descriptors(list, bind_point);
+        vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
+                root_parameter, bindings->descriptor_set, NULL, &buffer_info);
+        VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
+
+        assert(index < ARRAY_SIZE(bindings->push_descriptors));
+        bindings->push_descriptors[index].u.cbv.vk_buffer = buffer_info.buffer;
+        bindings->push_descriptors[index].u.cbv.offset = buffer_info.offset;
+        bindings->push_descriptor_dirty_mask |= 1u << index;
+        bindings->push_descriptor_active_mask |= 1u << index;
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootConstantBufferView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_cbv(list, VK_PIPELINE_BIND_POINT_COMPUTE, root_parameter_index, address);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootConstantBufferView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_cbv(list, VK_PIPELINE_BIND_POINT_GRAPHICS, root_parameter_index, address);
+}
+
+static void d3d12_command_list_set_root_descriptor(struct d3d12_command_list *list,
+        enum vkd3d_pipeline_bind_point bind_point, unsigned int index, D3D12_GPU_VIRTUAL_ADDRESS gpu_address)
+{
+    struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info;
+    const struct d3d12_root_parameter *root_parameter;
+    struct VkWriteDescriptorSet descriptor_write;
+    VkDevice vk_device = list->device->vk_device;
+    VkBufferView vk_buffer_view;
+
+    root_parameter = root_signature_get_root_descriptor(root_signature, index);
+    assert(root_parameter->parameter_type != D3D12_ROOT_PARAMETER_TYPE_CBV);
+
+    /* FIXME: Re-use buffer views. */
+    if (!vkd3d_create_raw_buffer_view(list->device, gpu_address, &vk_buffer_view))
+    {
+        ERR("Failed to create buffer view.\n");
+        return;
+    }
+
+    if (!(d3d12_command_allocator_add_buffer_view(list->allocator, vk_buffer_view)))
+    {
+        ERR("Failed to add buffer view.\n");
+        VK_CALL(vkDestroyBufferView(vk_device, vk_buffer_view, NULL));
+        return;
+    }
+
+    if (vk_info->KHR_push_descriptor)
+    {
+        vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
+                root_parameter, VK_NULL_HANDLE, &vk_buffer_view, NULL);
+        VK_CALL(vkCmdPushDescriptorSetKHR(list->vk_command_buffer, bindings->vk_bind_point,
+                root_signature->vk_pipeline_layout, 0, 1, &descriptor_write));
+    }
+    else
+    {
+        d3d12_command_list_prepare_descriptors(list, bind_point);
+        vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
+                root_parameter, bindings->descriptor_set, &vk_buffer_view,  NULL);
+        VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
+
+        assert(index < ARRAY_SIZE(bindings->push_descriptors));
+        bindings->push_descriptors[index].u.vk_buffer_view = vk_buffer_view;
+        bindings->push_descriptor_dirty_mask |= 1u << index;
+        bindings->push_descriptor_active_mask |= 1u << index;
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootShaderResourceView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_descriptor(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE,
+            root_parameter_index, address);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootShaderResourceView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_descriptor(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS,
+            root_parameter_index, address);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootUnorderedAccessView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_descriptor(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE,
+            root_parameter_index, address);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootUnorderedAccessView(
+        ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+
+    TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
+            iface, root_parameter_index, address);
+
+    d3d12_command_list_set_root_descriptor(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS,
+            root_parameter_index, address);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12GraphicsCommandList2 *iface,
+        const D3D12_INDEX_BUFFER_VIEW *view)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_resource *resource;
+    enum VkIndexType index_type;
+
+    TRACE("iface %p, view %p.\n", iface, view);
+
+    if (!view)
+    {
+        WARN("Ignoring NULL index buffer view.\n");
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    switch (view->Format)
+    {
+        case DXGI_FORMAT_R16_UINT:
+            index_type = VK_INDEX_TYPE_UINT16;
+            break;
+        case DXGI_FORMAT_R32_UINT:
+            index_type = VK_INDEX_TYPE_UINT32;
+            break;
+        default:
+            WARN("Invalid index format %#x.\n", view->Format);
+            return;
+    }
+
+    list->index_buffer_format = view->Format;
+
+    resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, view->BufferLocation);
+    VK_CALL(vkCmdBindIndexBuffer(list->vk_command_buffer, resource->u.vk_buffer,
+            view->BufferLocation - resource->gpu_address, index_type));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12GraphicsCommandList2 *iface,
+        UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct vkd3d_null_resources *null_resources;
+    struct vkd3d_gpu_va_allocator *gpu_va_allocator;
+    VkDeviceSize offsets[ARRAY_SIZE(list->strides)];
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkBuffer buffers[ARRAY_SIZE(list->strides)];
+    struct d3d12_resource *resource;
+    bool invalidate = false;
+    unsigned int i, stride;
+
+    TRACE("iface %p, start_slot %u, view_count %u, views %p.\n", iface, start_slot, view_count, views);
+
+    vk_procs = &list->device->vk_procs;
+    null_resources = &list->device->null_resources;
+    gpu_va_allocator = &list->device->gpu_va_allocator;
+
+    if (start_slot >= ARRAY_SIZE(list->strides) || view_count > ARRAY_SIZE(list->strides) - start_slot)
+    {
+        WARN("Invalid start slot %u / view count %u.\n", start_slot, view_count);
+        return;
+    }
+
+    for (i = 0; i < view_count; ++i)
+    {
+        if (views[i].BufferLocation)
+        {
+            resource = vkd3d_gpu_va_allocator_dereference(gpu_va_allocator, views[i].BufferLocation);
+            buffers[i] = resource->u.vk_buffer;
+            offsets[i] = views[i].BufferLocation - resource->gpu_address;
+            stride = views[i].StrideInBytes;
+        }
+        else
+        {
+            buffers[i] = null_resources->vk_buffer;
+            offsets[i] = 0;
+            stride = 0;
+        }
+
+        invalidate |= list->strides[start_slot + i] != stride;
+        list->strides[start_slot + i] = stride;
+    }
+
+    if (view_count)
+        VK_CALL(vkCmdBindVertexBuffers(list->vk_command_buffer, start_slot, view_count, buffers, offsets));
+
+    if (invalidate)
+        d3d12_command_list_invalidate_current_pipeline(list);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SOSetTargets(ID3D12GraphicsCommandList2 *iface,
+        UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    VkDeviceSize offsets[ARRAY_SIZE(list->so_counter_buffers)];
+    VkDeviceSize sizes[ARRAY_SIZE(list->so_counter_buffers)];
+    VkBuffer buffers[ARRAY_SIZE(list->so_counter_buffers)];
+    struct vkd3d_gpu_va_allocator *gpu_va_allocator;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_resource *resource;
+    unsigned int i, first, count;
+
+    TRACE("iface %p, start_slot %u, view_count %u, views %p.\n", iface, start_slot, view_count, views);
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (!list->device->vk_info.EXT_transform_feedback)
+    {
+        FIXME("Transform feedback is not supported by Vulkan implementation.\n");
+        return;
+    }
+
+    if (start_slot >= ARRAY_SIZE(buffers) || view_count > ARRAY_SIZE(buffers) - start_slot)
+    {
+        WARN("Invalid start slot %u / view count %u.\n", start_slot, view_count);
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+    gpu_va_allocator = &list->device->gpu_va_allocator;
+
+    count = 0;
+    first = start_slot;
+    for (i = 0; i < view_count; ++i)
+    {
+        if (views[i].BufferLocation && views[i].SizeInBytes)
+        {
+            resource = vkd3d_gpu_va_allocator_dereference(gpu_va_allocator, views[i].BufferLocation);
+            buffers[count] = resource->u.vk_buffer;
+            offsets[count] = views[i].BufferLocation - resource->gpu_address;
+            sizes[count] = views[i].SizeInBytes;
+
+            resource = vkd3d_gpu_va_allocator_dereference(gpu_va_allocator, views[i].BufferFilledSizeLocation);
+            list->so_counter_buffers[start_slot + i] = resource->u.vk_buffer;
+            list->so_counter_buffer_offsets[start_slot + i] = views[i].BufferFilledSizeLocation - resource->gpu_address;
+            ++count;
+        }
+        else
+        {
+            if (count)
+                VK_CALL(vkCmdBindTransformFeedbackBuffersEXT(list->vk_command_buffer, first, count, buffers, offsets, sizes));
+            count = 0;
+            first = start_slot + i + 1;
+
+            list->so_counter_buffers[start_slot + i] = VK_NULL_HANDLE;
+            list->so_counter_buffer_offsets[start_slot + i] = 0;
+
+            WARN("Trying to unbind transform feedback buffer %u. Ignoring.\n", start_slot + i);
+        }
+    }
+
+    if (count)
+        VK_CALL(vkCmdBindTransformFeedbackBuffersEXT(list->vk_command_buffer, first, count, buffers, offsets, sizes));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12GraphicsCommandList2 *iface,
+        UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors,
+        BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct d3d12_rtv_desc *rtv_desc;
+    const struct d3d12_dsv_desc *dsv_desc;
+    VkFormat prev_dsv_format;
+    struct vkd3d_view *view;
+    unsigned int i;
+
+    TRACE("iface %p, render_target_descriptor_count %u, render_target_descriptors %p, "
+            "single_descriptor_handle %#x, depth_stencil_descriptor %p.\n",
+            iface, render_target_descriptor_count, render_target_descriptors,
+            single_descriptor_handle, depth_stencil_descriptor);
+
+    if (render_target_descriptor_count > ARRAY_SIZE(list->rtvs))
+    {
+        WARN("Descriptor count %u > %zu, ignoring extra descriptors.\n",
+                render_target_descriptor_count, ARRAY_SIZE(list->rtvs));
+        render_target_descriptor_count = ARRAY_SIZE(list->rtvs);
+    }
+
+    list->fb_width = 0;
+    list->fb_height = 0;
+    list->fb_layer_count = 0;
+    for (i = 0; i < render_target_descriptor_count; ++i)
+    {
+        if (single_descriptor_handle)
+        {
+            if ((rtv_desc = d3d12_rtv_desc_from_cpu_handle(*render_target_descriptors)))
+                rtv_desc += i;
+        }
+        else
+        {
+            rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]);
+        }
+
+        if (!rtv_desc || !rtv_desc->resource)
+        {
+            WARN("RTV descriptor %u is not initialized.\n", i);
+            list->rtvs[i] = VK_NULL_HANDLE;
+            continue;
+        }
+
+        d3d12_command_list_track_resource_usage(list, rtv_desc->resource);
+
+        /* In D3D12 CPU descriptors are consumed when a command is recorded. */
+        view = rtv_desc->view;
+        if (!d3d12_command_allocator_add_view(list->allocator, view))
+        {
+            WARN("Failed to add view.\n");
+        }
+
+        list->rtvs[i] = view->u.vk_image_view;
+        list->fb_width = max(list->fb_width, rtv_desc->width);
+        list->fb_height = max(list->fb_height, rtv_desc->height);
+        list->fb_layer_count = max(list->fb_layer_count, rtv_desc->layer_count);
+    }
+
+    prev_dsv_format = list->dsv_format;
+    list->dsv = VK_NULL_HANDLE;
+    list->dsv_format = VK_FORMAT_UNDEFINED;
+    if (depth_stencil_descriptor)
+    {
+        if ((dsv_desc = d3d12_dsv_desc_from_cpu_handle(*depth_stencil_descriptor))
+                && dsv_desc->resource)
+        {
+            d3d12_command_list_track_resource_usage(list, dsv_desc->resource);
+
+            /* In D3D12 CPU descriptors are consumed when a command is recorded. */
+            view = dsv_desc->view;
+            if (!d3d12_command_allocator_add_view(list->allocator, view))
+            {
+                WARN("Failed to add view.\n");
+                list->dsv = VK_NULL_HANDLE;
+            }
+
+            list->dsv = view->u.vk_image_view;
+            list->fb_width = max(list->fb_width, dsv_desc->width);
+            list->fb_height = max(list->fb_height, dsv_desc->height);
+            list->fb_layer_count = max(list->fb_layer_count, dsv_desc->layer_count);
+            list->dsv_format = dsv_desc->format->vk_format;
+        }
+        else
+        {
+            WARN("DSV descriptor is not initialized.\n");
+        }
+    }
+
+    if (prev_dsv_format != list->dsv_format && d3d12_pipeline_state_has_unknown_dsv_format(list->state))
+        d3d12_command_list_invalidate_current_pipeline(list);
+
+    d3d12_command_list_invalidate_current_framebuffer(list);
+    d3d12_command_list_invalidate_current_render_pass(list);
+}
+
+static void d3d12_command_list_clear(struct d3d12_command_list *list,
+        const struct VkAttachmentDescription *attachment_desc,
+        const struct VkAttachmentReference *color_reference, const struct VkAttachmentReference *ds_reference,
+        struct vkd3d_view *view, size_t width, size_t height, unsigned int layer_count,
+        const union VkClearValue *clear_value, unsigned int rect_count, const D3D12_RECT *rects)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    struct VkSubpassDescription sub_pass_desc;
+    struct VkRenderPassCreateInfo pass_desc;
+    struct VkRenderPassBeginInfo begin_desc;
+    struct VkFramebufferCreateInfo fb_desc;
+    VkFramebuffer vk_framebuffer;
+    VkRenderPass vk_render_pass;
+    D3D12_RECT full_rect;
+    unsigned int i;
+    VkResult vr;
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (!rect_count)
+    {
+        full_rect.top = 0;
+        full_rect.left = 0;
+        full_rect.bottom = height;
+        full_rect.right = width;
+
+        rect_count = 1;
+        rects = &full_rect;
+    }
+
+    sub_pass_desc.flags = 0;
+    sub_pass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    sub_pass_desc.inputAttachmentCount = 0;
+    sub_pass_desc.pInputAttachments = NULL;
+    sub_pass_desc.colorAttachmentCount = !!color_reference;
+    sub_pass_desc.pColorAttachments = color_reference;
+    sub_pass_desc.pResolveAttachments = NULL;
+    sub_pass_desc.pDepthStencilAttachment = ds_reference;
+    sub_pass_desc.preserveAttachmentCount = 0;
+    sub_pass_desc.pPreserveAttachments = NULL;
+
+    pass_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    pass_desc.pNext = NULL;
+    pass_desc.flags = 0;
+    pass_desc.attachmentCount = 1;
+    pass_desc.pAttachments = attachment_desc;
+    pass_desc.subpassCount = 1;
+    pass_desc.pSubpasses = &sub_pass_desc;
+    pass_desc.dependencyCount = 0;
+    pass_desc.pDependencies = NULL;
+    if ((vr = VK_CALL(vkCreateRenderPass(list->device->vk_device, &pass_desc, NULL, &vk_render_pass))) < 0)
+    {
+        WARN("Failed to create Vulkan render pass, vr %d.\n", vr);
+        return;
+    }
+
+    if (!d3d12_command_allocator_add_render_pass(list->allocator, vk_render_pass))
+    {
+        WARN("Failed to add render pass.\n");
+        VK_CALL(vkDestroyRenderPass(list->device->vk_device, vk_render_pass, NULL));
+        return;
+    }
+
+    if (!d3d12_command_allocator_add_view(list->allocator, view))
+    {
+        WARN("Failed to add view.\n");
+    }
+
+    fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    fb_desc.pNext = NULL;
+    fb_desc.flags = 0;
+    fb_desc.renderPass = vk_render_pass;
+    fb_desc.attachmentCount = 1;
+    fb_desc.pAttachments = &view->u.vk_image_view;
+    fb_desc.width = width;
+    fb_desc.height = height;
+    fb_desc.layers = layer_count;
+    if ((vr = VK_CALL(vkCreateFramebuffer(list->device->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0)
+    {
+        WARN("Failed to create Vulkan framebuffer, vr %d.\n", vr);
+        return;
+    }
+
+    if (!d3d12_command_allocator_add_framebuffer(list->allocator, vk_framebuffer))
+    {
+        WARN("Failed to add framebuffer.\n");
+        VK_CALL(vkDestroyFramebuffer(list->device->vk_device, vk_framebuffer, NULL));
+        return;
+    }
+
+    begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    begin_desc.pNext = NULL;
+    begin_desc.renderPass = vk_render_pass;
+    begin_desc.framebuffer = vk_framebuffer;
+    begin_desc.clearValueCount = 1;
+    begin_desc.pClearValues = clear_value;
+
+    for (i = 0; i < rect_count; ++i)
+    {
+        begin_desc.renderArea.offset.x = rects[i].left;
+        begin_desc.renderArea.offset.y = rects[i].top;
+        begin_desc.renderArea.extent.width = rects[i].right - rects[i].left;
+        begin_desc.renderArea.extent.height = rects[i].bottom - rects[i].top;
+        VK_CALL(vkCmdBeginRenderPass(list->vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE));
+        VK_CALL(vkCmdEndRenderPass(list->vk_command_buffer));
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12GraphicsCommandList2 *iface,
+        D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, float depth, UINT8 stencil,
+        UINT rect_count, const D3D12_RECT *rects)
+{
+    const union VkClearValue clear_value = {.depthStencil = {depth, stencil}};
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct d3d12_dsv_desc *dsv_desc = d3d12_dsv_desc_from_cpu_handle(dsv);
+    struct VkAttachmentDescription attachment_desc;
+    struct VkAttachmentReference ds_reference;
+
+    TRACE("iface %p, dsv %#lx, flags %#x, depth %.8e, stencil 0x%02x, rect_count %u, rects %p.\n",
+            iface, dsv.ptr, flags, depth, stencil, rect_count, rects);
+
+    d3d12_command_list_track_resource_usage(list, dsv_desc->resource);
+
+    attachment_desc.flags = 0;
+    attachment_desc.format = dsv_desc->format->vk_format;
+    attachment_desc.samples = dsv_desc->sample_count;
+    if (flags & D3D12_CLEAR_FLAG_DEPTH)
+    {
+        attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+        attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    }
+    else
+    {
+        attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+        attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    }
+    if (flags & D3D12_CLEAR_FLAG_STENCIL)
+    {
+        attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+        attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+    }
+    else
+    {
+        attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+        attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    }
+    attachment_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+    attachment_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+    ds_reference.attachment = 0;
+    ds_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+    d3d12_command_list_clear(list, &attachment_desc, NULL, &ds_reference,
+            dsv_desc->view, dsv_desc->width, dsv_desc->height, dsv_desc->layer_count,
+            &clear_value, rect_count, rects);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12GraphicsCommandList2 *iface,
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const struct d3d12_rtv_desc *rtv_desc = d3d12_rtv_desc_from_cpu_handle(rtv);
+    struct VkAttachmentDescription attachment_desc;
+    struct VkAttachmentReference color_reference;
+    VkClearValue clear_value;
+
+    TRACE("iface %p, rtv %#lx, color %p, rect_count %u, rects %p.\n",
+            iface, rtv.ptr, color, rect_count, rects);
+
+    d3d12_command_list_track_resource_usage(list, rtv_desc->resource);
+
+    attachment_desc.flags = 0;
+    attachment_desc.format = rtv_desc->format->vk_format;
+    attachment_desc.samples = rtv_desc->sample_count;
+    attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+    attachment_desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    color_reference.attachment = 0;
+    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    if (rtv_desc->format->type == VKD3D_FORMAT_TYPE_UINT)
+    {
+        clear_value.color.uint32[0] = max(0, color[0]);
+        clear_value.color.uint32[1] = max(0, color[1]);
+        clear_value.color.uint32[2] = max(0, color[2]);
+        clear_value.color.uint32[3] = max(0, color[3]);
+    }
+    else if (rtv_desc->format->type == VKD3D_FORMAT_TYPE_SINT)
+    {
+        clear_value.color.int32[0] = color[0];
+        clear_value.color.int32[1] = color[1];
+        clear_value.color.int32[2] = color[2];
+        clear_value.color.int32[3] = color[3];
+    }
+    else
+    {
+        clear_value.color.float32[0] = color[0];
+        clear_value.color.float32[1] = color[1];
+        clear_value.color.float32[2] = color[2];
+        clear_value.color.float32[3] = color[3];
+    }
+
+    d3d12_command_list_clear(list, &attachment_desc, &color_reference, NULL,
+            rtv_desc->view, rtv_desc->width, rtv_desc->height, rtv_desc->layer_count,
+            &clear_value, rect_count, rects);
+}
+
+struct vkd3d_uav_clear_pipeline
+{
+    VkDescriptorSetLayout vk_set_layout;
+    VkPipelineLayout vk_pipeline_layout;
+    VkPipeline vk_pipeline;
+    VkExtent3D group_size;
+};
+
+static void vkd3d_uav_clear_state_get_buffer_pipeline(const struct vkd3d_uav_clear_state *state,
+        enum vkd3d_format_type format_type, struct vkd3d_uav_clear_pipeline *info)
+{
+    const struct vkd3d_uav_clear_pipelines *pipelines;
+
+    pipelines = format_type == VKD3D_FORMAT_TYPE_UINT ? &state->pipelines_uint : &state->pipelines_float;
+    info->vk_set_layout = state->vk_set_layout_buffer;
+    info->vk_pipeline_layout = state->vk_pipeline_layout_buffer;
+    info->vk_pipeline = pipelines->buffer;
+    info->group_size = (VkExtent3D){128, 1, 1};
+}
+
+static void vkd3d_uav_clear_state_get_image_pipeline(const struct vkd3d_uav_clear_state *state,
+        VkImageViewType image_view_type, enum vkd3d_format_type format_type, struct vkd3d_uav_clear_pipeline *info)
+{
+    const struct vkd3d_uav_clear_pipelines *pipelines;
+
+    pipelines = format_type == VKD3D_FORMAT_TYPE_UINT ? &state->pipelines_uint : &state->pipelines_float;
+    info->vk_set_layout = state->vk_set_layout_image;
+    info->vk_pipeline_layout = state->vk_pipeline_layout_image;
+
+    switch (image_view_type)
+    {
+        case VK_IMAGE_VIEW_TYPE_1D:
+            info->vk_pipeline = pipelines->image_1d;
+            info->group_size = (VkExtent3D){64, 1, 1};
+            break;
+
+        case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
+            info->vk_pipeline = pipelines->image_1d_array;
+            info->group_size = (VkExtent3D){64, 1, 1};
+            break;
+
+        case VK_IMAGE_VIEW_TYPE_2D:
+            info->vk_pipeline = pipelines->image_2d;
+            info->group_size = (VkExtent3D){8, 8, 1};
+            break;
+
+        case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
+            info->vk_pipeline = pipelines->image_2d_array;
+            info->group_size = (VkExtent3D){8, 8, 1};
+            break;
+
+        case VK_IMAGE_VIEW_TYPE_3D:
+            info->vk_pipeline = pipelines->image_3d;
+            info->group_size = (VkExtent3D){8, 8, 1};
+            break;
+
+        default:
+            ERR("Unhandled view type %#x.\n", image_view_type);
+            info->vk_pipeline = VK_NULL_HANDLE;
+            info->group_size = (VkExtent3D){0, 0, 0};
+            break;
+    }
+}
+
+static void d3d12_command_list_clear_uav(struct d3d12_command_list *list,
+        struct d3d12_resource *resource, struct vkd3d_view *view, const VkClearColorValue *clear_colour,
+        unsigned int rect_count, const D3D12_RECT *rects)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+    unsigned int i, miplevel_idx, layer_count;
+    struct vkd3d_uav_clear_pipeline pipeline;
+    struct vkd3d_uav_clear_args clear_args;
+    VkDescriptorImageInfo image_info;
+    D3D12_RECT full_rect, curr_rect;
+    VkWriteDescriptorSet write_set;
+
+    d3d12_command_list_track_resource_usage(list, resource);
+    d3d12_command_list_end_current_render_pass(list);
+
+    d3d12_command_list_invalidate_current_pipeline(list);
+    d3d12_command_list_invalidate_bindings(list, list->state);
+    d3d12_command_list_invalidate_root_parameters(list, VK_PIPELINE_BIND_POINT_COMPUTE);
+
+    if (!d3d12_command_allocator_add_view(list->allocator, view))
+        WARN("Failed to add view.\n");
+
+    clear_args.colour = *clear_colour;
+
+    write_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    write_set.pNext = NULL;
+    write_set.dstBinding = 0;
+    write_set.dstArrayElement = 0;
+    write_set.descriptorCount = 1;
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        write_set.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+        write_set.pImageInfo = NULL;
+        write_set.pBufferInfo = NULL;
+        write_set.pTexelBufferView = &view->u.vk_buffer_view;
+
+        miplevel_idx = 0;
+        layer_count = 1;
+        vkd3d_uav_clear_state_get_buffer_pipeline(&list->device->uav_clear_state,
+                view->format->type, &pipeline);
+    }
+    else
+    {
+        image_info.sampler = VK_NULL_HANDLE;
+        image_info.imageView = view->u.vk_image_view;
+        image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+        write_set.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+        write_set.pImageInfo = &image_info;
+        write_set.pBufferInfo = NULL;
+        write_set.pTexelBufferView = NULL;
+
+        miplevel_idx = view->info.texture.miplevel_idx;
+        layer_count = view->info.texture.vk_view_type == VK_IMAGE_VIEW_TYPE_3D
+                ? d3d12_resource_desc_get_depth(&resource->desc, miplevel_idx)
+                : view->info.texture.layer_count;
+        vkd3d_uav_clear_state_get_image_pipeline(&list->device->uav_clear_state,
+                view->info.texture.vk_view_type, view->format->type, &pipeline);
+    }
+
+    if (!(write_set.dstSet = d3d12_command_allocator_allocate_descriptor_set(
+            list->allocator, pipeline.vk_set_layout)))
+    {
+        ERR("Failed to allocate descriptor set.\n");
+        return;
+    }
+
+    VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &write_set, 0, NULL));
+
+    full_rect.left = 0;
+    full_rect.right = d3d12_resource_desc_get_width(&resource->desc, miplevel_idx);
+    full_rect.top = 0;
+    full_rect.bottom = d3d12_resource_desc_get_height(&resource->desc, miplevel_idx);
+
+    if (!rect_count)
+    {
+        rects = &full_rect;
+        rect_count = 1;
+    }
+
+    VK_CALL(vkCmdBindPipeline(list->vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.vk_pipeline));
+
+    VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
+            pipeline.vk_pipeline_layout, 0, 1, &write_set.dstSet, 0, NULL));
+
+    for (i = 0; i < rect_count; ++i)
+    {
+        /* Clamp to the actual resource region and skip empty rectangles. */
+        curr_rect.left = max(rects[i].left, full_rect.left);
+        curr_rect.top = max(rects[i].top, full_rect.top);
+        curr_rect.right = min(rects[i].right, full_rect.right);
+        curr_rect.bottom = min(rects[i].bottom, full_rect.bottom);
+
+        if (curr_rect.left >= curr_rect.right || curr_rect.top >= curr_rect.bottom)
+            continue;
+
+        clear_args.offset.x = curr_rect.left;
+        clear_args.offset.y = curr_rect.top;
+        clear_args.extent.width = curr_rect.right - curr_rect.left;
+        clear_args.extent.height = curr_rect.bottom - curr_rect.top;
+
+        VK_CALL(vkCmdPushConstants(list->vk_command_buffer, pipeline.vk_pipeline_layout,
+                VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(clear_args), &clear_args));
+
+        VK_CALL(vkCmdDispatch(list->vk_command_buffer,
+                vkd3d_compute_workgroup_count(clear_args.extent.width, pipeline.group_size.width),
+                vkd3d_compute_workgroup_count(clear_args.extent.height, pipeline.group_size.height),
+                vkd3d_compute_workgroup_count(layer_count, pipeline.group_size.depth)));
+    }
+}
+
+static const struct vkd3d_format *vkd3d_fixup_clear_uav_uint_colour(struct d3d12_device *device,
+        DXGI_FORMAT dxgi_format, VkClearColorValue *colour)
+{
+    switch (dxgi_format)
+    {
+        case DXGI_FORMAT_R11G11B10_FLOAT:
+            colour->uint32[0] = (colour->uint32[0] & 0x7ff)
+                    | ((colour->uint32[1] & 0x7ff) << 11)
+                    | ((colour->uint32[2] & 0x3ff) << 22);
+            return vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+
+        default:
+            return NULL;
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList2 *iface,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource,
+        const UINT values[4], UINT rect_count, const D3D12_RECT *rects)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_device *device = list->device;
+    struct vkd3d_view *view, *uint_view = NULL;
+    struct vkd3d_texture_view_desc view_desc;
+    const struct vkd3d_format *uint_format;
+    struct d3d12_resource *resource_impl;
+    VkClearColorValue colour;
+
+    TRACE("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p.\n",
+            iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
+
+    resource_impl = unsafe_impl_from_ID3D12Resource(resource);
+    view = d3d12_desc_from_cpu_handle(cpu_handle)->u.view;
+    memcpy(colour.uint32, values, sizeof(colour.uint32));
+
+    if (view->format->type != VKD3D_FORMAT_TYPE_UINT)
+    {
+        if (!(uint_format = vkd3d_find_uint_format(device, view->format->dxgi_format))
+                && !(uint_format = vkd3d_fixup_clear_uav_uint_colour(device, view->format->dxgi_format, &colour)))
+        {
+            ERR("Unhandled format %#x.\n", view->format->dxgi_format);
+            return;
+        }
+
+        if (d3d12_resource_is_buffer(resource_impl))
+        {
+            if (!vkd3d_create_buffer_view(device, resource_impl->u.vk_buffer, uint_format,
+                    view->info.buffer.offset, view->info.buffer.size, &uint_view))
+            {
+                ERR("Failed to create buffer view.\n");
+                return;
+            }
+        }
+        else
+        {
+            memset(&view_desc, 0, sizeof(view_desc));
+            view_desc.view_type = view->info.texture.vk_view_type;
+            view_desc.format = uint_format;
+            view_desc.miplevel_idx = view->info.texture.miplevel_idx;
+            view_desc.miplevel_count = 1;
+            view_desc.layer_idx = view->info.texture.layer_idx;
+            view_desc.layer_count = view->info.texture.layer_count;
+
+            if (!vkd3d_create_texture_view(device, resource_impl->u.vk_image, &view_desc, &uint_view))
+            {
+                ERR("Failed to create image view.\n");
+                return;
+            }
+        }
+        view = uint_view;
+    }
+
+    d3d12_command_list_clear_uav(list, resource_impl, view, &colour, rect_count, rects);
+
+    if (uint_view)
+        vkd3d_view_decref(uint_view, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList2 *iface,
+        D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource,
+        const float values[4], UINT rect_count, const D3D12_RECT *rects)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *resource_impl;
+    VkClearColorValue colour;
+    struct vkd3d_view *view;
+
+    TRACE("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p.\n",
+            iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
+
+    resource_impl = unsafe_impl_from_ID3D12Resource(resource);
+    view = d3d12_desc_from_cpu_handle(cpu_handle)->u.view;
+    memcpy(colour.float32, values, sizeof(colour.float32));
+
+    d3d12_command_list_clear_uav(list, resource_impl, view, &colour, rect_count, rects);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *resource, const D3D12_DISCARD_REGION *region)
+{
+    FIXME_ONCE("iface %p, resource %p, region %p stub!\n", iface, resource, region);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_BeginQuery(ID3D12GraphicsCommandList2 *iface,
+        ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkQueryControlFlags flags = 0;
+
+    TRACE("iface %p, heap %p, type %#x, index %u.\n", iface, heap, type, index);
+
+    vk_procs = &list->device->vk_procs;
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    VK_CALL(vkCmdResetQueryPool(list->vk_command_buffer, query_heap->vk_query_pool, index, 1));
+
+    if (type == D3D12_QUERY_TYPE_OCCLUSION)
+        flags = VK_QUERY_CONTROL_PRECISE_BIT;
+
+    if (D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3)
+    {
+        unsigned int stream_index = type - D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0;
+        VK_CALL(vkCmdBeginQueryIndexedEXT(list->vk_command_buffer,
+                query_heap->vk_query_pool, index, flags, stream_index));
+        return;
+    }
+
+    VK_CALL(vkCmdBeginQuery(list->vk_command_buffer, query_heap->vk_query_pool, index, flags));
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_EndQuery(ID3D12GraphicsCommandList2 *iface,
+        ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap);
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, heap %p, type %#x, index %u.\n", iface, heap, type, index);
+
+    vk_procs = &list->device->vk_procs;
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    d3d12_query_heap_mark_result_as_available(query_heap, index);
+
+    if (type == D3D12_QUERY_TYPE_TIMESTAMP)
+    {
+        VK_CALL(vkCmdResetQueryPool(list->vk_command_buffer, query_heap->vk_query_pool, index, 1));
+        VK_CALL(vkCmdWriteTimestamp(list->vk_command_buffer,
+                VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_heap->vk_query_pool, index));
+        return;
+    }
+
+    if (D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3)
+    {
+        unsigned int stream_index = type - D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0;
+        VK_CALL(vkCmdEndQueryIndexedEXT(list->vk_command_buffer,
+                query_heap->vk_query_pool, index, stream_index));
+        return;
+    }
+
+    VK_CALL(vkCmdEndQuery(list->vk_command_buffer, query_heap->vk_query_pool, index));
+}
+
+static size_t get_query_stride(D3D12_QUERY_TYPE type)
+{
+    if (type == D3D12_QUERY_TYPE_PIPELINE_STATISTICS)
+        return sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS);
+
+    if (D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3)
+        return sizeof(D3D12_QUERY_DATA_SO_STATISTICS);
+
+    return sizeof(uint64_t);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12GraphicsCommandList2 *iface,
+        ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count,
+        ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset)
+{
+    const struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap);
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *buffer = unsafe_impl_from_ID3D12Resource(dst_buffer);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    unsigned int i, first, count;
+    VkDeviceSize offset, stride;
+
+    TRACE("iface %p, heap %p, type %#x, start_index %u, query_count %u, "
+            "dst_buffer %p, aligned_dst_buffer_offset %#"PRIx64".\n",
+            iface, heap, type, start_index, query_count,
+            dst_buffer, aligned_dst_buffer_offset);
+
+    vk_procs = &list->device->vk_procs;
+
+    /* Vulkan is less strict than D3D12 here. Vulkan implementations are free
+     * to return any non-zero result for binary occlusion with at least one
+     * sample passing, while D3D12 guarantees that the result is 1 then.
+     *
+     * For example, the Nvidia binary blob drivers on Linux seem to always
+     * count precisely, even when it was signalled that non-precise is enough.
+     */
+    if (type == D3D12_QUERY_TYPE_BINARY_OCCLUSION)
+        FIXME_ONCE("D3D12 guarantees binary occlusion queries result in only 0 and 1.\n");
+
+    if (!d3d12_resource_is_buffer(buffer))
+    {
+        WARN("Destination resource is not a buffer.\n");
+        return;
+    }
+
+    d3d12_command_list_end_current_render_pass(list);
+
+    stride = get_query_stride(type);
+
+    count = 0;
+    first = start_index;
+    offset = aligned_dst_buffer_offset;
+    for (i = 0; i < query_count; ++i)
+    {
+        if (d3d12_query_heap_is_result_available(query_heap, start_index + i))
+        {
+            ++count;
+        }
+        else
+        {
+            if (count)
+            {
+                VK_CALL(vkCmdCopyQueryPoolResults(list->vk_command_buffer,
+                        query_heap->vk_query_pool, first, count, buffer->u.vk_buffer,
+                        offset, stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT));
+            }
+            count = 0;
+            first = start_index + i;
+            offset = aligned_dst_buffer_offset + i * stride;
+
+            /* We cannot copy query results if a query was not issued:
+             *
+             *   "If the query does not become available in a finite amount of
+             *   time (e.g. due to not issuing a query since the last reset),
+             *   a VK_ERROR_DEVICE_LOST error may occur."
+             */
+            VK_CALL(vkCmdFillBuffer(list->vk_command_buffer,
+                    buffer->u.vk_buffer, offset, stride, 0x00000000));
+
+            ++first;
+            offset += stride;
+        }
+    }
+
+    if (count)
+    {
+        VK_CALL(vkCmdCopyQueryPoolResults(list->vk_command_buffer,
+                query_heap->vk_query_pool, first, count, buffer->u.vk_buffer,
+                offset, stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT));
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetPredication(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *resource = unsafe_impl_from_ID3D12Resource(buffer);
+    const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info;
+    const struct vkd3d_vk_device_procs *vk_procs;
+
+    TRACE("iface %p, buffer %p, aligned_buffer_offset %#"PRIx64", operation %#x.\n",
+            iface, buffer, aligned_buffer_offset, operation);
+
+    if (!vk_info->EXT_conditional_rendering)
+    {
+        FIXME("Vulkan conditional rendering extension not present. Conditional rendering not supported.\n");
+        return;
+    }
+
+    vk_procs = &list->device->vk_procs;
+
+    /* FIXME: Add support for conditional rendering in render passes. */
+    d3d12_command_list_end_current_render_pass(list);
+
+    if (resource)
+    {
+        VkConditionalRenderingBeginInfoEXT cond_info;
+
+        if (aligned_buffer_offset & (sizeof(uint64_t) - 1))
+        {
+            WARN("Unaligned predicate argument buffer offset %#"PRIx64".\n", aligned_buffer_offset);
+            return;
+        }
+
+        if (!d3d12_resource_is_buffer(resource))
+        {
+            WARN("Predicate arguments must be stored in a buffer resource.\n");
+            return;
+        }
+
+        FIXME_ONCE("Predication doesn't support clear and copy commands, "
+                "and predication values are treated as 32-bit values.\n");
+
+        cond_info.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
+        cond_info.pNext = NULL;
+        cond_info.buffer = resource->u.vk_buffer;
+        cond_info.offset = aligned_buffer_offset;
+        switch (operation)
+        {
+            case D3D12_PREDICATION_OP_EQUAL_ZERO:
+                cond_info.flags = 0;
+                break;
+
+            case D3D12_PREDICATION_OP_NOT_EQUAL_ZERO:
+                cond_info.flags = VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
+                break;
+
+            default:
+                FIXME("Unhandled predication operation %#x.\n", operation);
+                return;
+        }
+
+        if (list->is_predicated)
+            VK_CALL(vkCmdEndConditionalRenderingEXT(list->vk_command_buffer));
+        VK_CALL(vkCmdBeginConditionalRenderingEXT(list->vk_command_buffer, &cond_info));
+        list->is_predicated = true;
+    }
+    else if (list->is_predicated)
+    {
+        VK_CALL(vkCmdEndConditionalRenderingEXT(list->vk_command_buffer));
+        list->is_predicated = false;
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetMarker(ID3D12GraphicsCommandList2 *iface,
+        UINT metadata, const void *data, UINT size)
+{
+    FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_BeginEvent(ID3D12GraphicsCommandList2 *iface,
+        UINT metadata, const void *data, UINT size)
+{
+    FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_EndEvent(ID3D12GraphicsCommandList2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+}
+
+STATIC_ASSERT(sizeof(VkDispatchIndirectCommand) == sizeof(D3D12_DISPATCH_ARGUMENTS));
+STATIC_ASSERT(sizeof(VkDrawIndexedIndirectCommand) == sizeof(D3D12_DRAW_INDEXED_ARGUMENTS));
+STATIC_ASSERT(sizeof(VkDrawIndirectCommand) == sizeof(D3D12_DRAW_ARGUMENTS));
+
+static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsCommandList2 *iface,
+        ID3D12CommandSignature *command_signature, UINT max_command_count, ID3D12Resource *arg_buffer,
+        UINT64 arg_buffer_offset, ID3D12Resource *count_buffer, UINT64 count_buffer_offset)
+{
+    struct d3d12_command_signature *sig_impl = unsafe_impl_from_ID3D12CommandSignature(command_signature);
+    struct d3d12_resource *count_impl = unsafe_impl_from_ID3D12Resource(count_buffer);
+    struct d3d12_resource *arg_impl = unsafe_impl_from_ID3D12Resource(arg_buffer);
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    const D3D12_COMMAND_SIGNATURE_DESC *signature_desc;
+    const struct vkd3d_vk_device_procs *vk_procs;
+    unsigned int i;
+
+    TRACE("iface %p, command_signature %p, max_command_count %u, arg_buffer %p, "
+            "arg_buffer_offset %#"PRIx64", count_buffer %p, count_buffer_offset %#"PRIx64".\n",
+            iface, command_signature, max_command_count, arg_buffer, arg_buffer_offset,
+            count_buffer, count_buffer_offset);
+
+    vk_procs = &list->device->vk_procs;
+
+    if (count_buffer && !list->device->vk_info.KHR_draw_indirect_count)
+    {
+        FIXME("Count buffers not supported by Vulkan implementation.\n");
+        return;
+    }
+
+    signature_desc = &sig_impl->desc;
+    for (i = 0; i < signature_desc->NumArgumentDescs; ++i)
+    {
+        const D3D12_INDIRECT_ARGUMENT_DESC *arg_desc = &signature_desc->pArgumentDescs[i];
+
+        switch (arg_desc->Type)
+        {
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW:
+                if (!d3d12_command_list_begin_render_pass(list))
+                {
+                    WARN("Failed to begin render pass, ignoring draw.\n");
+                    break;
+                }
+
+                if (count_buffer)
+                {
+                    VK_CALL(vkCmdDrawIndirectCountKHR(list->vk_command_buffer, arg_impl->u.vk_buffer,
+                            arg_buffer_offset, count_impl->u.vk_buffer, count_buffer_offset,
+                            max_command_count, signature_desc->ByteStride));
+                }
+                else
+                {
+                    VK_CALL(vkCmdDrawIndirect(list->vk_command_buffer, arg_impl->u.vk_buffer,
+                            arg_buffer_offset, max_command_count, signature_desc->ByteStride));
+                }
+                break;
+
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED:
+                if (!d3d12_command_list_begin_render_pass(list))
+                {
+                    WARN("Failed to begin render pass, ignoring draw.\n");
+                    break;
+                }
+
+                d3d12_command_list_check_index_buffer_strip_cut_value(list);
+
+                if (count_buffer)
+                {
+                    VK_CALL(vkCmdDrawIndexedIndirectCountKHR(list->vk_command_buffer, arg_impl->u.vk_buffer,
+                            arg_buffer_offset, count_impl->u.vk_buffer, count_buffer_offset,
+                            max_command_count, signature_desc->ByteStride));
+                }
+                else
+                {
+                    VK_CALL(vkCmdDrawIndexedIndirect(list->vk_command_buffer, arg_impl->u.vk_buffer,
+                            arg_buffer_offset, max_command_count, signature_desc->ByteStride));
+                }
+                break;
+
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH:
+                if (max_command_count != 1)
+                    FIXME("Ignoring command count %u.\n", max_command_count);
+
+                if (count_buffer)
+                {
+                    FIXME("Count buffers not supported for indirect dispatch.\n");
+                    break;
+                }
+
+                if (!d3d12_command_list_update_compute_state(list))
+                {
+                    WARN("Failed to update compute state, ignoring dispatch.\n");
+                    return;
+                }
+
+                VK_CALL(vkCmdDispatchIndirect(list->vk_command_buffer,
+                        arg_impl->u.vk_buffer, arg_buffer_offset));
+                break;
+
+            default:
+                FIXME("Ignoring unhandled argument type %#x.\n", arg_desc->Type);
+                break;
+        }
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst_buffer, UINT64 dst_offset,
+        ID3D12Resource *src_buffer, UINT64 src_offset,
+        UINT dependent_resource_count, ID3D12Resource * const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges)
+{
+    FIXME("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, "
+            "src_offset %#"PRIx64", dependent_resource_count %u, "
+            "dependent_resources %p, dependent_sub_resource_ranges %p stub!\n",
+            iface, dst_buffer, dst_offset, src_buffer, src_offset,
+            dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst_buffer, UINT64 dst_offset,
+        ID3D12Resource *src_buffer, UINT64 src_offset,
+        UINT dependent_resource_count, ID3D12Resource * const *dependent_resources,
+        const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges)
+{
+    FIXME("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, "
+            "src_offset %#"PRIx64", dependent_resource_count %u, "
+            "dependent_resources %p, dependent_sub_resource_ranges %p stub!\n",
+            iface, dst_buffer, dst_offset, src_buffer, src_offset,
+            dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_OMSetDepthBounds(ID3D12GraphicsCommandList2 *iface,
+        FLOAT min, FLOAT max)
+{
+    FIXME("iface %p, min %.8e, max %.8e stub!\n", iface, min, max);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetSamplePositions(ID3D12GraphicsCommandList2 *iface,
+        UINT sample_count, UINT pixel_count, D3D12_SAMPLE_POSITION *sample_positions)
+{
+    FIXME("iface %p, sample_count %u, pixel_count %u, sample_positions %p stub!\n",
+            iface, sample_count, pixel_count, sample_positions);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresourceRegion(ID3D12GraphicsCommandList2 *iface,
+        ID3D12Resource *dst_resource, UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y,
+        ID3D12Resource *src_resource, UINT src_sub_resource_idx,
+        D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode)
+{
+    FIXME("iface %p, dst_resource %p, dst_sub_resource_idx %u, "
+            "dst_x %u, dst_y %u, src_resource %p, src_sub_resource_idx %u, "
+            "src_rect %p, format %#x, mode %#x stub!\n",
+            iface, dst_resource, dst_sub_resource_idx, dst_x, dst_y,
+            src_resource, src_sub_resource_idx, src_rect, format, mode);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_SetViewInstanceMask(ID3D12GraphicsCommandList2 *iface, UINT mask)
+{
+    FIXME("iface %p, mask %#x stub!\n", iface, mask);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_list_WriteBufferImmediate(ID3D12GraphicsCommandList2 *iface,
+        UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters,
+        const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes)
+{
+    struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface);
+    struct d3d12_resource *resource;
+    unsigned int i;
+
+    FIXME("iface %p, count %u, parameters %p, modes %p stub!\n", iface, count, parameters, modes);
+
+    for (i = 0; i < count; ++i)
+    {
+        resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, parameters[i].Dest);
+        d3d12_command_list_track_resource_usage(list, resource);
+    }
+}
+
+static const struct ID3D12GraphicsCommandList2Vtbl d3d12_command_list_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_command_list_QueryInterface,
+    d3d12_command_list_AddRef,
+    d3d12_command_list_Release,
+    /* ID3D12Object methods */
+    d3d12_command_list_GetPrivateData,
+    d3d12_command_list_SetPrivateData,
+    d3d12_command_list_SetPrivateDataInterface,
+    d3d12_command_list_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_command_list_GetDevice,
+    /* ID3D12CommandList methods */
+    d3d12_command_list_GetType,
+    /* ID3D12GraphicsCommandList methods */
+    d3d12_command_list_Close,
+    d3d12_command_list_Reset,
+    d3d12_command_list_ClearState,
+    d3d12_command_list_DrawInstanced,
+    d3d12_command_list_DrawIndexedInstanced,
+    d3d12_command_list_Dispatch,
+    d3d12_command_list_CopyBufferRegion,
+    d3d12_command_list_CopyTextureRegion,
+    d3d12_command_list_CopyResource,
+    d3d12_command_list_CopyTiles,
+    d3d12_command_list_ResolveSubresource,
+    d3d12_command_list_IASetPrimitiveTopology,
+    d3d12_command_list_RSSetViewports,
+    d3d12_command_list_RSSetScissorRects,
+    d3d12_command_list_OMSetBlendFactor,
+    d3d12_command_list_OMSetStencilRef,
+    d3d12_command_list_SetPipelineState,
+    d3d12_command_list_ResourceBarrier,
+    d3d12_command_list_ExecuteBundle,
+    d3d12_command_list_SetDescriptorHeaps,
+    d3d12_command_list_SetComputeRootSignature,
+    d3d12_command_list_SetGraphicsRootSignature,
+    d3d12_command_list_SetComputeRootDescriptorTable,
+    d3d12_command_list_SetGraphicsRootDescriptorTable,
+    d3d12_command_list_SetComputeRoot32BitConstant,
+    d3d12_command_list_SetGraphicsRoot32BitConstant,
+    d3d12_command_list_SetComputeRoot32BitConstants,
+    d3d12_command_list_SetGraphicsRoot32BitConstants,
+    d3d12_command_list_SetComputeRootConstantBufferView,
+    d3d12_command_list_SetGraphicsRootConstantBufferView,
+    d3d12_command_list_SetComputeRootShaderResourceView,
+    d3d12_command_list_SetGraphicsRootShaderResourceView,
+    d3d12_command_list_SetComputeRootUnorderedAccessView,
+    d3d12_command_list_SetGraphicsRootUnorderedAccessView,
+    d3d12_command_list_IASetIndexBuffer,
+    d3d12_command_list_IASetVertexBuffers,
+    d3d12_command_list_SOSetTargets,
+    d3d12_command_list_OMSetRenderTargets,
+    d3d12_command_list_ClearDepthStencilView,
+    d3d12_command_list_ClearRenderTargetView,
+    d3d12_command_list_ClearUnorderedAccessViewUint,
+    d3d12_command_list_ClearUnorderedAccessViewFloat,
+    d3d12_command_list_DiscardResource,
+    d3d12_command_list_BeginQuery,
+    d3d12_command_list_EndQuery,
+    d3d12_command_list_ResolveQueryData,
+    d3d12_command_list_SetPredication,
+    d3d12_command_list_SetMarker,
+    d3d12_command_list_BeginEvent,
+    d3d12_command_list_EndEvent,
+    d3d12_command_list_ExecuteIndirect,
+    /* ID3D12GraphicsCommandList1 methods */
+    d3d12_command_list_AtomicCopyBufferUINT,
+    d3d12_command_list_AtomicCopyBufferUINT64,
+    d3d12_command_list_OMSetDepthBounds,
+    d3d12_command_list_SetSamplePositions,
+    d3d12_command_list_ResolveSubresourceRegion,
+    d3d12_command_list_SetViewInstanceMask,
+    /* ID3D12GraphicsCommandList2 methods */
+    d3d12_command_list_WriteBufferImmediate,
+};
+
+static struct d3d12_command_list *unsafe_impl_from_ID3D12CommandList(ID3D12CommandList *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == (struct ID3D12CommandListVtbl *)&d3d12_command_list_vtbl);
+    return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList2_iface);
+}
+
+static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d3d12_device *device,
+        D3D12_COMMAND_LIST_TYPE type, struct d3d12_command_allocator *allocator,
+        ID3D12PipelineState *initial_pipeline_state)
+{
+    HRESULT hr;
+
+    list->ID3D12GraphicsCommandList2_iface.lpVtbl = &d3d12_command_list_vtbl;
+    list->refcount = 1;
+
+    list->type = type;
+
+    if (FAILED(hr = vkd3d_private_store_init(&list->private_store)))
+        return hr;
+
+    d3d12_device_add_ref(list->device = device);
+
+    list->allocator = allocator;
+
+    if (SUCCEEDED(hr = d3d12_command_allocator_allocate_command_buffer(allocator, list)))
+    {
+        list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS].vk_uav_counter_views = NULL;
+        list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE].vk_uav_counter_views = NULL;
+        d3d12_command_list_reset_state(list, initial_pipeline_state);
+    }
+    else
+    {
+        vkd3d_private_store_destroy(&list->private_store);
+        d3d12_device_release(device);
+    }
+
+    return hr;
+}
+
+HRESULT d3d12_command_list_create(struct d3d12_device *device,
+        UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *allocator_iface,
+        ID3D12PipelineState *initial_pipeline_state, struct d3d12_command_list **list)
+{
+    struct d3d12_command_allocator *allocator;
+    struct d3d12_command_list *object;
+    HRESULT hr;
+
+    if (!(allocator = unsafe_impl_from_ID3D12CommandAllocator(allocator_iface)))
+    {
+        WARN("Command allocator is NULL.\n");
+        return E_INVALIDARG;
+    }
+
+    if (allocator->type != type)
+    {
+        WARN("Command list types do not match (allocator %#x, list %#x).\n",
+                allocator->type, type);
+        return E_INVALIDARG;
+    }
+
+    debug_ignored_node_mask(node_mask);
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_command_list_init(object, device, type, allocator, initial_pipeline_state)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created command list %p.\n", object);
+
+    *list = object;
+
+    return S_OK;
+}
+
+/* ID3D12CommandQueue */
+static inline struct d3d12_command_queue *impl_from_ID3D12CommandQueue(ID3D12CommandQueue *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_command_queue, ID3D12CommandQueue_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12CommandQueue *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12CommandQueue)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12CommandQueue_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_queue_AddRef(ID3D12CommandQueue *iface)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    ULONG refcount = InterlockedIncrement(&command_queue->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", command_queue, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_queue_Release(ID3D12CommandQueue *iface)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    ULONG refcount = InterlockedDecrement(&command_queue->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", command_queue, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = command_queue->device;
+
+        vkd3d_private_store_destroy(&command_queue->private_store);
+
+        vkd3d_free(command_queue);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetPrivateData(ID3D12CommandQueue *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&command_queue->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_SetPrivateData(ID3D12CommandQueue *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&command_queue->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_SetPrivateDataInterface(ID3D12CommandQueue *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&command_queue->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_SetName(ID3D12CommandQueue *iface, const WCHAR *name)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    VkQueue vk_queue;
+    HRESULT hr;
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, command_queue->device->wchar_size));
+
+    if (!(vk_queue = vkd3d_queue_acquire(command_queue->vkd3d_queue)))
+    {
+        ERR("Failed to acquire queue %p.\n", command_queue->vkd3d_queue);
+        return E_FAIL;
+    }
+
+    hr = vkd3d_set_vk_object_name(command_queue->device, (uint64_t)(uintptr_t)vk_queue,
+            VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, name);
+    vkd3d_queue_release(command_queue->vkd3d_queue);
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetDevice(ID3D12CommandQueue *iface, REFIID iid, void **device)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(command_queue->device, iid, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_UpdateTileMappings(ID3D12CommandQueue *iface,
+        ID3D12Resource *resource, UINT region_count,
+        const D3D12_TILED_RESOURCE_COORDINATE *region_start_coordinates,
+        const D3D12_TILE_REGION_SIZE *region_sizes,
+        UINT range_count,
+        const D3D12_TILE_RANGE_FLAGS *range_flags,
+        UINT *heap_range_offsets,
+        UINT *range_tile_counts,
+        D3D12_TILE_MAPPING_FLAGS flags)
+{
+    FIXME("iface %p, resource %p, region_count %u, region_start_coordinates %p, "
+            "region_sizes %p, range_count %u, range_flags %p, heap_range_offsets %p, "
+            "range_tile_counts %p, flags %#x stub!\n",
+            iface, resource, region_count, region_start_coordinates, region_sizes, range_count,
+            range_flags, heap_range_offsets, range_tile_counts, flags);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_CopyTileMappings(ID3D12CommandQueue *iface,
+        ID3D12Resource *dst_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate,
+        ID3D12Resource *src_resource,
+        const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate,
+        const D3D12_TILE_REGION_SIZE *region_size,
+        D3D12_TILE_MAPPING_FLAGS flags)
+{
+    FIXME("iface %p, dst_resource %p, dst_region_start_coordinate %p, "
+            "src_resource %p, src_region_start_coordinate %p, region_size %p, flags %#x stub!\n",
+            iface, dst_resource, dst_region_start_coordinate, src_resource,
+            src_region_start_coordinate, region_size, flags);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12CommandQueue *iface,
+        UINT command_list_count, ID3D12CommandList * const *command_lists)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct d3d12_command_list *cmd_list;
+    struct VkSubmitInfo submit_desc;
+    VkCommandBuffer *buffers;
+    VkQueue vk_queue;
+    unsigned int i;
+    VkResult vr;
+
+    TRACE("iface %p, command_list_count %u, command_lists %p.\n",
+            iface, command_list_count, command_lists);
+
+    vk_procs = &command_queue->device->vk_procs;
+
+    if (!(buffers = vkd3d_calloc(command_list_count, sizeof(*buffers))))
+    {
+        ERR("Failed to allocate command buffer array.\n");
+        return;
+    }
+
+    for (i = 0; i < command_list_count; ++i)
+    {
+        cmd_list = unsafe_impl_from_ID3D12CommandList(command_lists[i]);
+
+        if (cmd_list->is_recording)
+        {
+            d3d12_device_mark_as_removed(command_queue->device, DXGI_ERROR_INVALID_CALL,
+                    "Command list %p is in recording state.\n", command_lists[i]);
+            vkd3d_free(buffers);
+            return;
+        }
+
+        buffers[i] = cmd_list->vk_command_buffer;
+    }
+
+    submit_desc.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_desc.pNext = NULL;
+    submit_desc.waitSemaphoreCount = 0;
+    submit_desc.pWaitSemaphores = NULL;
+    submit_desc.pWaitDstStageMask = NULL;
+    submit_desc.commandBufferCount = command_list_count;
+    submit_desc.pCommandBuffers = buffers;
+    submit_desc.signalSemaphoreCount = 0;
+    submit_desc.pSignalSemaphores = NULL;
+
+    if (!(vk_queue = vkd3d_queue_acquire(command_queue->vkd3d_queue)))
+    {
+        ERR("Failed to acquire queue %p.\n", command_queue->vkd3d_queue);
+        vkd3d_free(buffers);
+        return;
+    }
+
+    if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_desc, VK_NULL_HANDLE))) < 0)
+        ERR("Failed to submit queue(s), vr %d.\n", vr);
+
+    vkd3d_queue_release(command_queue->vkd3d_queue);
+
+    vkd3d_free(buffers);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_SetMarker(ID3D12CommandQueue *iface,
+        UINT metadata, const void *data, UINT size)
+{
+    FIXME("iface %p, metadata %#x, data %p, size %u stub!\n",
+            iface, metadata, data, size);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_BeginEvent(ID3D12CommandQueue *iface,
+        UINT metadata, const void *data, UINT size)
+{
+    FIXME("iface %p, metatdata %#x, data %p, size %u stub!\n",
+            iface, metadata, data, size);
+}
+
+static void STDMETHODCALLTYPE d3d12_command_queue_EndEvent(ID3D12CommandQueue *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *iface,
+        ID3D12Fence *fence_iface, UINT64 value)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkSemaphore vk_semaphore = VK_NULL_HANDLE;
+    VkFence vk_fence = VK_NULL_HANDLE;
+    struct vkd3d_queue *vkd3d_queue;
+    struct d3d12_device *device;
+    struct d3d12_fence *fence;
+    VkSubmitInfo submit_info;
+    uint64_t sequence_number;
+    VkQueue vk_queue;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("iface %p, fence %p, value %#"PRIx64".\n", iface, fence_iface, value);
+
+    device = command_queue->device;
+    vk_procs = &device->vk_procs;
+    vkd3d_queue = command_queue->vkd3d_queue;
+
+    fence = unsafe_impl_from_ID3D12Fence(fence_iface);
+
+    if ((vr = d3d12_fence_create_vk_fence(fence, &vk_fence)) < 0)
+    {
+        WARN("Failed to create Vulkan fence, vr %d.\n", vr);
+        goto fail_vkresult;
+    }
+
+    if (!(vk_queue = vkd3d_queue_acquire(vkd3d_queue)))
+    {
+        ERR("Failed to acquire queue %p.\n", vkd3d_queue);
+        hr = E_FAIL;
+        goto fail;
+    }
+
+    if ((vr = vkd3d_queue_create_vk_semaphore_locked(vkd3d_queue, device, &vk_semaphore)) < 0)
+    {
+        ERR("Failed to create Vulkan semaphore, vr %d.\n", vr);
+        vk_semaphore = VK_NULL_HANDLE;
+    }
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = NULL;
+    submit_info.waitSemaphoreCount = 0;
+    submit_info.pWaitSemaphores = NULL;
+    submit_info.pWaitDstStageMask = NULL;
+    submit_info.commandBufferCount = 0;
+    submit_info.pCommandBuffers = NULL;
+    submit_info.signalSemaphoreCount = vk_semaphore ? 1 : 0;
+    submit_info.pSignalSemaphores = &vk_semaphore;
+
+    if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, vk_fence))) >= 0)
+    {
+        sequence_number = ++vkd3d_queue->submitted_sequence_number;
+
+        /* We don't expect to overrun the 64-bit counter, but we handle it gracefully anyway. */
+        if (!sequence_number)
+            sequence_number = vkd3d_queue_reset_sequence_number_locked(vkd3d_queue);
+    }
+
+    vkd3d_queue_release(vkd3d_queue);
+
+    if (vr < 0)
+    {
+        WARN("Failed to submit signal operation, vr %d.\n", vr);
+        goto fail_vkresult;
+    }
+
+    if (vk_semaphore && SUCCEEDED(hr = d3d12_fence_add_vk_semaphore(fence, vk_semaphore, vk_fence, value)))
+        vk_semaphore = VK_NULL_HANDLE;
+
+    vr = VK_CALL(vkGetFenceStatus(device->vk_device, vk_fence));
+    if (vr == VK_NOT_READY)
+    {
+        if (SUCCEEDED(hr = vkd3d_enqueue_gpu_fence(&device->fence_worker, vk_fence, fence, value, vkd3d_queue, sequence_number)))
+            vk_fence = VK_NULL_HANDLE;
+    }
+    else if (vr == VK_SUCCESS)
+    {
+        TRACE("Already signaled %p, value %#"PRIx64".\n", fence, value);
+        hr = d3d12_fence_signal(fence, value, vk_fence);
+        vk_fence = VK_NULL_HANDLE;
+        vkd3d_queue_update_sequence_number(vkd3d_queue, sequence_number, device);
+    }
+    else
+    {
+        FIXME("Failed to get fence status, vr %d.\n", vr);
+        hr = hresult_from_vk_result(vr);
+    }
+
+    if (vk_fence || vk_semaphore)
+    {
+        /* In case of an unexpected failure, try to safely destroy Vulkan objects. */
+        vkd3d_queue_wait_idle(vkd3d_queue, vk_procs);
+        goto fail;
+    }
+
+    return hr;
+
+fail_vkresult:
+    hr = hresult_from_vk_result(vr);
+fail:
+    VK_CALL(vkDestroyFence(device->vk_device, vk_fence, NULL));
+    VK_CALL(vkDestroySemaphore(device->vk_device, vk_semaphore, NULL));
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Wait(ID3D12CommandQueue *iface,
+        ID3D12Fence *fence_iface, UINT64 value)
+{
+    static const VkPipelineStageFlagBits wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct vkd3d_signaled_semaphore *semaphore;
+    uint64_t completed_value = 0;
+    struct vkd3d_queue *queue;
+    struct d3d12_fence *fence;
+    VkSubmitInfo submit_info;
+    VkQueue vk_queue;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("iface %p, fence %p, value %#"PRIx64".\n", iface, fence_iface, value);
+
+    vk_procs = &command_queue->device->vk_procs;
+    queue = command_queue->vkd3d_queue;
+
+    fence = unsafe_impl_from_ID3D12Fence(fence_iface);
+
+    semaphore = d3d12_fence_acquire_vk_semaphore(fence, value, &completed_value);
+    if (!semaphore && completed_value >= value)
+    {
+        /* We don't get a Vulkan semaphore if the fence was signaled on CPU. */
+        TRACE("Already signaled %p, value %#"PRIx64".\n", fence, completed_value);
+        return S_OK;
+    }
+
+    if (!(vk_queue = vkd3d_queue_acquire(queue)))
+    {
+        ERR("Failed to acquire queue %p.\n", queue);
+        hr = E_FAIL;
+        goto fail;
+    }
+
+    if (!semaphore)
+    {
+        if (command_queue->last_waited_fence == fence && command_queue->last_waited_fence_value >= value)
+        {
+            WARN("Already waited on fence %p, value %#"PRIx64".\n", fence, value);
+        }
+        else
+        {
+            FIXME("Failed to acquire Vulkan semaphore for fence %p, value %#"PRIx64
+                    ", completed value %#"PRIx64".\n", fence, value, completed_value);
+        }
+
+        vkd3d_queue_release(queue);
+        return S_OK;
+    }
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = NULL;
+    submit_info.waitSemaphoreCount = 1;
+    submit_info.pWaitSemaphores = &semaphore->vk_semaphore;
+    submit_info.pWaitDstStageMask = &wait_stage_mask;
+    submit_info.commandBufferCount = 0;
+    submit_info.pCommandBuffers = NULL;
+    submit_info.signalSemaphoreCount = 0;
+    submit_info.pSignalSemaphores = NULL;
+
+    if (!vkd3d_array_reserve((void **)&queue->semaphores, &queue->semaphores_size,
+            queue->semaphore_count + 1, sizeof(*queue->semaphores)))
+    {
+        ERR("Failed to allocate memory for semaphore.\n");
+        vkd3d_queue_release(queue);
+        hr = E_OUTOFMEMORY;
+        goto fail;
+    }
+
+    if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE))) >= 0)
+    {
+        queue->semaphores[queue->semaphore_count].vk_semaphore = semaphore->vk_semaphore;
+        queue->semaphores[queue->semaphore_count].sequence_number = queue->submitted_sequence_number + 1;
+        ++queue->semaphore_count;
+
+        command_queue->last_waited_fence = fence;
+        command_queue->last_waited_fence_value = value;
+    }
+
+    vkd3d_queue_release(queue);
+
+    if (vr < 0)
+    {
+        WARN("Failed to submit wait operation, vr %d.\n", vr);
+        hr = hresult_from_vk_result(vr);
+        goto fail;
+    }
+
+    d3d12_fence_remove_vk_semaphore(fence, semaphore);
+    return S_OK;
+
+fail:
+    d3d12_fence_release_vk_semaphore(fence, semaphore);
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetTimestampFrequency(ID3D12CommandQueue *iface,
+        UINT64 *frequency)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    struct d3d12_device *device = command_queue->device;
+
+    TRACE("iface %p, frequency %p.\n", iface, frequency);
+
+    if (!command_queue->vkd3d_queue->timestamp_bits)
+    {
+        WARN("Timestamp queries not supported.\n");
+        return E_FAIL;
+    }
+
+    *frequency = 1000000000 / device->vk_info.device_limits.timestampPeriod;
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetClockCalibration(ID3D12CommandQueue *iface,
+        UINT64 *gpu_timestamp, UINT64 *cpu_timestamp)
+{
+    FIXME("iface %p, gpu_timestamp %p, cpu_timestamp %p stub!\n",
+            iface, gpu_timestamp, cpu_timestamp);
+
+    return E_NOTIMPL;
+}
+
+static D3D12_COMMAND_QUEUE_DESC * STDMETHODCALLTYPE d3d12_command_queue_GetDesc(ID3D12CommandQueue *iface,
+        D3D12_COMMAND_QUEUE_DESC *desc)
+{
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+
+    TRACE("iface %p, desc %p.\n", iface, desc);
+
+    *desc = command_queue->desc;
+    return desc;
+}
+
+static const struct ID3D12CommandQueueVtbl d3d12_command_queue_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_command_queue_QueryInterface,
+    d3d12_command_queue_AddRef,
+    d3d12_command_queue_Release,
+    /* ID3D12Object methods */
+    d3d12_command_queue_GetPrivateData,
+    d3d12_command_queue_SetPrivateData,
+    d3d12_command_queue_SetPrivateDataInterface,
+    d3d12_command_queue_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_command_queue_GetDevice,
+    /* ID3D12CommandQueue methods */
+    d3d12_command_queue_UpdateTileMappings,
+    d3d12_command_queue_CopyTileMappings,
+    d3d12_command_queue_ExecuteCommandLists,
+    d3d12_command_queue_SetMarker,
+    d3d12_command_queue_BeginEvent,
+    d3d12_command_queue_EndEvent,
+    d3d12_command_queue_Signal,
+    d3d12_command_queue_Wait,
+    d3d12_command_queue_GetTimestampFrequency,
+    d3d12_command_queue_GetClockCalibration,
+    d3d12_command_queue_GetDesc,
+};
+
+static HRESULT d3d12_command_queue_init(struct d3d12_command_queue *queue,
+        struct d3d12_device *device, const D3D12_COMMAND_QUEUE_DESC *desc)
+{
+    HRESULT hr;
+
+    queue->ID3D12CommandQueue_iface.lpVtbl = &d3d12_command_queue_vtbl;
+    queue->refcount = 1;
+
+    queue->desc = *desc;
+    if (!queue->desc.NodeMask)
+        queue->desc.NodeMask = 0x1;
+
+    if (!(queue->vkd3d_queue = d3d12_device_get_vkd3d_queue(device, desc->Type)))
+        return E_NOTIMPL;
+
+    queue->last_waited_fence = NULL;
+    queue->last_waited_fence_value = 0;
+
+    if (desc->Priority == D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME)
+    {
+        FIXME("Global realtime priority is not implemented.\n");
+        return E_NOTIMPL;
+    }
+
+    if (desc->Priority)
+        FIXME("Ignoring priority %#x.\n", desc->Priority);
+    if (desc->Flags)
+        FIXME("Ignoring flags %#x.\n", desc->Flags);
+
+    if (FAILED(hr = vkd3d_private_store_init(&queue->private_store)))
+        return hr;
+
+    d3d12_device_add_ref(queue->device = device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_command_queue_create(struct d3d12_device *device,
+        const D3D12_COMMAND_QUEUE_DESC *desc, struct d3d12_command_queue **queue)
+{
+    struct d3d12_command_queue *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_command_queue_init(object, device, desc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created command queue %p.\n", object);
+
+    *queue = object;
+
+    return S_OK;
+}
+
+uint32_t vkd3d_get_vk_queue_family_index(ID3D12CommandQueue *queue)
+{
+    struct d3d12_command_queue *d3d12_queue = impl_from_ID3D12CommandQueue(queue);
+
+    return d3d12_queue->vkd3d_queue->vk_family_index;
+}
+
+VkQueue vkd3d_acquire_vk_queue(ID3D12CommandQueue *queue)
+{
+    struct d3d12_command_queue *d3d12_queue = impl_from_ID3D12CommandQueue(queue);
+
+    return vkd3d_queue_acquire(d3d12_queue->vkd3d_queue);
+}
+
+void vkd3d_release_vk_queue(ID3D12CommandQueue *queue)
+{
+    struct d3d12_command_queue *d3d12_queue = impl_from_ID3D12CommandQueue(queue);
+
+    return vkd3d_queue_release(d3d12_queue->vkd3d_queue);
+}
+
+/* ID3D12CommandSignature */
+static inline struct d3d12_command_signature *impl_from_ID3D12CommandSignature(ID3D12CommandSignature *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_command_signature, ID3D12CommandSignature_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_QueryInterface(ID3D12CommandSignature *iface,
+        REFIID iid, void **out)
+{
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_ID3D12CommandSignature)
+            || IsEqualGUID(iid, &IID_ID3D12Pageable)
+            || IsEqualGUID(iid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(iid, &IID_ID3D12Object)
+            || IsEqualGUID(iid, &IID_IUnknown))
+    {
+        ID3D12CommandSignature_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_signature_AddRef(ID3D12CommandSignature *iface)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+    ULONG refcount = InterlockedIncrement(&signature->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", signature, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_command_signature_Release(ID3D12CommandSignature *iface)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+    ULONG refcount = InterlockedDecrement(&signature->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", signature, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = signature->device;
+
+        vkd3d_private_store_destroy(&signature->private_store);
+
+        vkd3d_free((void *)signature->desc.pArgumentDescs);
+        vkd3d_free(signature);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_GetPrivateData(ID3D12CommandSignature *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&signature->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_SetPrivateData(ID3D12CommandSignature *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&signature->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_SetPrivateDataInterface(ID3D12CommandSignature *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&signature->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_SetName(ID3D12CommandSignature *iface, const WCHAR *name)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, signature->device->wchar_size));
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_signature_GetDevice(ID3D12CommandSignature *iface, REFIID iid, void **device)
+{
+    struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(signature->device, iid, device);
+}
+
+static const struct ID3D12CommandSignatureVtbl d3d12_command_signature_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_command_signature_QueryInterface,
+    d3d12_command_signature_AddRef,
+    d3d12_command_signature_Release,
+    /* ID3D12Object methods */
+    d3d12_command_signature_GetPrivateData,
+    d3d12_command_signature_SetPrivateData,
+    d3d12_command_signature_SetPrivateDataInterface,
+    d3d12_command_signature_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_command_signature_GetDevice,
+};
+
+struct d3d12_command_signature *unsafe_impl_from_ID3D12CommandSignature(ID3D12CommandSignature *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_command_signature_vtbl);
+    return CONTAINING_RECORD(iface, struct d3d12_command_signature, ID3D12CommandSignature_iface);
+}
+
+HRESULT d3d12_command_signature_create(struct d3d12_device *device, const D3D12_COMMAND_SIGNATURE_DESC *desc,
+        struct d3d12_command_signature **signature)
+{
+    struct d3d12_command_signature *object;
+    unsigned int i;
+    HRESULT hr;
+
+    for (i = 0; i < desc->NumArgumentDescs; ++i)
+    {
+        const D3D12_INDIRECT_ARGUMENT_DESC *argument_desc = &desc->pArgumentDescs[i];
+        switch (argument_desc->Type)
+        {
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW:
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED:
+            case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH:
+                if (i != desc->NumArgumentDescs - 1)
+                {
+                    WARN("Draw/dispatch must be the last element of a command signature.\n");
+                    return E_INVALIDARG;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->ID3D12CommandSignature_iface.lpVtbl = &d3d12_command_signature_vtbl;
+    object->refcount = 1;
+
+    object->desc = *desc;
+    if (!(object->desc.pArgumentDescs = vkd3d_calloc(desc->NumArgumentDescs, sizeof(*desc->pArgumentDescs))))
+    {
+        vkd3d_free(object);
+        return E_OUTOFMEMORY;
+    }
+    memcpy((void *)object->desc.pArgumentDescs, desc->pArgumentDescs,
+            desc->NumArgumentDescs * sizeof(*desc->pArgumentDescs));
+
+    if (FAILED(hr = vkd3d_private_store_init(&object->private_store)))
+    {
+        vkd3d_free((void *)object->desc.pArgumentDescs);
+        vkd3d_free(object);
+        return hr;
+    }
+
+    d3d12_device_add_ref(object->device = device);
+
+    TRACE("Created command signature %p.\n", object);
+
+    *signature = object;
+
+    return S_OK;
+}
diff --git a/dlls/vkd3d/libs/vkd3d/device.c b/dlls/vkd3d/libs/vkd3d/device.c
new file mode 100644
index 00000000000..bef6477347f
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/device.c
@@ -0,0 +1,3857 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_private.h"
+#include "vkd3d_version.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+
+static void *vkd3d_dlopen(const char *name)
+{
+    return dlopen(name, RTLD_NOW);
+}
+
+static void *vkd3d_dlsym(void *handle, const char *symbol)
+{
+    return dlsym(handle, symbol);
+}
+
+static int vkd3d_dlclose(void *handle)
+{
+    return dlclose(handle);
+}
+
+static const char *vkd3d_dlerror(void)
+{
+    return dlerror();
+}
+#else
+static void *vkd3d_dlopen(const char *name)
+{
+    FIXME("Not implemented for this platform.\n");
+    return NULL;
+}
+
+static void *vkd3d_dlsym(void *handle, const char *symbol)
+{
+    return NULL;
+}
+
+static int vkd3d_dlclose(void *handle)
+{
+    return 0;
+}
+
+static const char *vkd3d_dlerror(void)
+{
+    return "Not implemented for this platform.\n";
+}
+#endif
+
+struct vkd3d_struct
+{
+    enum vkd3d_structure_type type;
+    const void *next;
+};
+
+#define vkd3d_find_struct(c, t) vkd3d_find_struct_(c, VKD3D_STRUCTURE_TYPE_##t)
+static const void *vkd3d_find_struct_(const struct vkd3d_struct *chain,
+        enum vkd3d_structure_type type)
+{
+    while (chain)
+    {
+        if (chain->type == type)
+            return chain;
+
+        chain = chain->next;
+    }
+
+    return NULL;
+}
+
+static uint32_t vkd3d_get_vk_version(void)
+{
+    int major, minor;
+
+    vkd3d_parse_version(PACKAGE_VERSION, &major, &minor);
+    return VK_MAKE_VERSION(major, minor, 0);
+}
+
+struct vkd3d_optional_extension_info
+{
+    const char *extension_name;
+    ptrdiff_t vulkan_info_offset;
+    bool is_debug_only;
+};
+
+#define VK_EXTENSION(name, member) \
+        {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member)}
+#define VK_DEBUG_EXTENSION(name, member) \
+        {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), true}
+
+static const struct vkd3d_optional_extension_info optional_instance_extensions[] =
+{
+    /* KHR extensions */
+    VK_EXTENSION(KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, KHR_get_physical_device_properties2),
+    /* EXT extensions */
+    VK_DEBUG_EXTENSION(EXT_DEBUG_REPORT, EXT_debug_report),
+};
+
+static const char * const required_device_extensions[] =
+{
+    VK_KHR_MAINTENANCE1_EXTENSION_NAME,
+    VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
+};
+
+static const struct vkd3d_optional_extension_info optional_device_extensions[] =
+{
+    /* KHR extensions */
+    VK_EXTENSION(KHR_DEDICATED_ALLOCATION, KHR_dedicated_allocation),
+    VK_EXTENSION(KHR_DRAW_INDIRECT_COUNT, KHR_draw_indirect_count),
+    VK_EXTENSION(KHR_GET_MEMORY_REQUIREMENTS_2, KHR_get_memory_requirements2),
+    VK_EXTENSION(KHR_IMAGE_FORMAT_LIST, KHR_image_format_list),
+    VK_EXTENSION(KHR_MAINTENANCE3, KHR_maintenance3),
+    VK_EXTENSION(KHR_PUSH_DESCRIPTOR, KHR_push_descriptor),
+    /* EXT extensions */
+    VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering),
+    VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker),
+    VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable),
+    VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
+    VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation),
+    VK_EXTENSION(EXT_TEXEL_BUFFER_ALIGNMENT, EXT_texel_buffer_alignment),
+    VK_EXTENSION(EXT_TRANSFORM_FEEDBACK, EXT_transform_feedback),
+    VK_EXTENSION(EXT_VERTEX_ATTRIBUTE_DIVISOR, EXT_vertex_attribute_divisor),
+};
+
+static unsigned int get_spec_version(const VkExtensionProperties *extensions,
+        unsigned int count, const char *extension_name)
+{
+    unsigned int i;
+
+    for (i = 0; i < count; ++i)
+    {
+        if (!strcmp(extensions[i].extensionName, extension_name))
+            return extensions[i].specVersion;
+    }
+    return 0;
+}
+
+static bool is_extension_disabled(const char *extension_name)
+{
+    const char *disabled_extensions;
+
+    if (!(disabled_extensions = getenv("VKD3D_DISABLE_EXTENSIONS")))
+        return false;
+
+    return vkd3d_debug_list_has_member(disabled_extensions, extension_name);
+}
+
+static bool has_extension(const VkExtensionProperties *extensions,
+        unsigned int count, const char *extension_name)
+{
+    unsigned int i;
+
+    for (i = 0; i < count; ++i)
+    {
+        if (is_extension_disabled(extension_name))
+        {
+            WARN("Extension %s is disabled.\n", debugstr_a(extension_name));
+            continue;
+        }
+        if (!strcmp(extensions[i].extensionName, extension_name))
+            return true;
+    }
+    return false;
+}
+
+static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensions, unsigned int count,
+        const char * const *required_extensions, unsigned int required_extension_count,
+        const struct vkd3d_optional_extension_info *optional_extensions, unsigned int optional_extension_count,
+        const char * const *user_extensions, unsigned int user_extension_count,
+        const char * const *optional_user_extensions, unsigned int optional_user_extension_count,
+        bool *user_extension_supported, struct vkd3d_vulkan_info *vulkan_info, const char *extension_type,
+        bool is_debug_enabled)
+{
+    unsigned int extension_count = 0;
+    unsigned int i;
+
+    for (i = 0; i < required_extension_count; ++i)
+    {
+        if (!has_extension(extensions, count, required_extensions[i]))
+            ERR("Required %s extension %s is not supported.\n",
+                    extension_type, debugstr_a(required_extensions[i]));
+        ++extension_count;
+    }
+
+    for (i = 0; i < optional_extension_count; ++i)
+    {
+        const char *extension_name = optional_extensions[i].extension_name;
+        ptrdiff_t offset = optional_extensions[i].vulkan_info_offset;
+        bool *supported = (void *)((uintptr_t)vulkan_info + offset);
+
+        if (!is_debug_enabled && optional_extensions[i].is_debug_only)
+        {
+            *supported = false;
+            TRACE("Skipping debug-only extension %s.\n", debugstr_a(extension_name));
+            continue;
+        }
+
+        if ((*supported = has_extension(extensions, count, extension_name)))
+        {
+            TRACE("Found %s extension.\n", debugstr_a(extension_name));
+            ++extension_count;
+        }
+    }
+
+    for (i = 0; i < user_extension_count; ++i)
+    {
+        if (!has_extension(extensions, count, user_extensions[i]))
+            ERR("Required user %s extension %s is not supported.\n",
+                    extension_type, debugstr_a(user_extensions[i]));
+        ++extension_count;
+    }
+
+    assert(!optional_user_extension_count || user_extension_supported);
+    for (i = 0; i < optional_user_extension_count; ++i)
+    {
+        if (has_extension(extensions, count, optional_user_extensions[i]))
+        {
+            user_extension_supported[i] = true;
+            ++extension_count;
+        }
+        else
+        {
+            user_extension_supported[i] = false;
+            WARN("Optional user %s extension %s is not supported.\n",
+                    extension_type, debugstr_a(optional_user_extensions[i]));
+        }
+    }
+
+    return extension_count;
+}
+
+static unsigned int vkd3d_append_extension(const char *extensions[],
+        unsigned int extension_count, const char *extension_name)
+{
+    unsigned int i;
+
+    /* avoid duplicates */
+    for (i = 0; i < extension_count; ++i)
+    {
+        if (!strcmp(extensions[i], extension_name))
+            return extension_count;
+    }
+
+    extensions[extension_count++] = extension_name;
+    return extension_count;
+}
+
+static unsigned int vkd3d_enable_extensions(const char *extensions[],
+        const char * const *required_extensions, unsigned int required_extension_count,
+        const struct vkd3d_optional_extension_info *optional_extensions, unsigned int optional_extension_count,
+        const char * const *user_extensions, unsigned int user_extension_count,
+        const char * const *optional_user_extensions, unsigned int optional_user_extension_count,
+        bool *user_extension_supported, const struct vkd3d_vulkan_info *vulkan_info)
+{
+    unsigned int extension_count = 0;
+    unsigned int i;
+
+    for (i = 0; i < required_extension_count; ++i)
+    {
+        extensions[extension_count++] = required_extensions[i];
+    }
+    for (i = 0; i < optional_extension_count; ++i)
+    {
+        ptrdiff_t offset = optional_extensions[i].vulkan_info_offset;
+        const bool *supported = (void *)((uintptr_t)vulkan_info + offset);
+
+        if (*supported)
+            extensions[extension_count++] = optional_extensions[i].extension_name;
+    }
+
+    for (i = 0; i < user_extension_count; ++i)
+    {
+        extension_count = vkd3d_append_extension(extensions, extension_count, user_extensions[i]);
+    }
+    assert(!optional_user_extension_count || user_extension_supported);
+    for (i = 0; i < optional_user_extension_count; ++i)
+    {
+        if (!user_extension_supported[i])
+            continue;
+        extension_count = vkd3d_append_extension(extensions, extension_count, optional_user_extensions[i]);
+    }
+
+    return extension_count;
+}
+
+static HRESULT vkd3d_init_instance_caps(struct vkd3d_instance *instance,
+        const struct vkd3d_instance_create_info *create_info,
+        uint32_t *instance_extension_count, bool **user_extension_supported)
+{
+    const struct vkd3d_vk_global_procs *vk_procs = &instance->vk_global_procs;
+    const struct vkd3d_optional_instance_extensions_info *optional_extensions;
+    struct vkd3d_vulkan_info *vulkan_info = &instance->vk_info;
+    VkExtensionProperties *vk_extensions;
+    uint32_t count;
+    VkResult vr;
+
+    memset(vulkan_info, 0, sizeof(*vulkan_info));
+    *instance_extension_count = 0;
+
+    if ((vr = vk_procs->vkEnumerateInstanceExtensionProperties(NULL, &count, NULL)) < 0)
+    {
+        ERR("Failed to enumerate instance extensions, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+    if (!count)
+        return S_OK;
+
+    if (!(vk_extensions = vkd3d_calloc(count, sizeof(*vk_extensions))))
+        return E_OUTOFMEMORY;
+
+    TRACE("Enumerating %u instance extensions.\n", count);
+    if ((vr = vk_procs->vkEnumerateInstanceExtensionProperties(NULL, &count, vk_extensions)) < 0)
+    {
+        ERR("Failed to enumerate instance extensions, vr %d.\n", vr);
+        vkd3d_free(vk_extensions);
+        return hresult_from_vk_result(vr);
+    }
+
+    optional_extensions = vkd3d_find_struct(create_info->next, OPTIONAL_INSTANCE_EXTENSIONS_INFO);
+    if (optional_extensions && optional_extensions->extension_count)
+    {
+        if (!(*user_extension_supported = vkd3d_calloc(optional_extensions->extension_count, sizeof(bool))))
+        {
+            vkd3d_free(vk_extensions);
+            return E_OUTOFMEMORY;
+        }
+    }
+    else
+    {
+        *user_extension_supported = NULL;
+    }
+
+    *instance_extension_count = vkd3d_check_extensions(vk_extensions, count, NULL, 0,
+            optional_instance_extensions, ARRAY_SIZE(optional_instance_extensions),
+            create_info->instance_extensions, create_info->instance_extension_count,
+            optional_extensions ? optional_extensions->extensions : NULL,
+            optional_extensions ? optional_extensions->extension_count : 0,
+            *user_extension_supported, vulkan_info, "instance",
+            instance->config_flags & VKD3D_CONFIG_FLAG_VULKAN_DEBUG);
+
+    vkd3d_free(vk_extensions);
+    return S_OK;
+}
+
+static HRESULT vkd3d_init_vk_global_procs(struct vkd3d_instance *instance,
+        PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr)
+{
+    HRESULT hr;
+
+    if (!vkGetInstanceProcAddr)
+    {
+        if (!(instance->libvulkan = vkd3d_dlopen(SONAME_LIBVULKAN)))
+        {
+            ERR("Failed to load libvulkan: %s.\n", vkd3d_dlerror());
+            return E_FAIL;
+        }
+
+        if (!(vkGetInstanceProcAddr = vkd3d_dlsym(instance->libvulkan, "vkGetInstanceProcAddr")))
+        {
+            ERR("Could not load function pointer for vkGetInstanceProcAddr().\n");
+            vkd3d_dlclose(instance->libvulkan);
+            instance->libvulkan = NULL;
+            return E_FAIL;
+        }
+    }
+    else
+    {
+        instance->libvulkan = NULL;
+    }
+
+    if (FAILED(hr = vkd3d_load_vk_global_procs(&instance->vk_global_procs, vkGetInstanceProcAddr)))
+    {
+        if (instance->libvulkan)
+            vkd3d_dlclose(instance->libvulkan);
+        instance->libvulkan = NULL;
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static VkBool32 VKAPI_PTR vkd3d_debug_report_callback(VkDebugReportFlagsEXT flags,
+        VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location,
+        int32_t message_code, const char *layer_prefix, const char *message, void *user_data)
+{
+    FIXME("%s\n", debugstr_a(message));
+    return VK_FALSE;
+}
+
+static void vkd3d_init_debug_report(struct vkd3d_instance *instance)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &instance->vk_procs;
+    VkDebugReportCallbackCreateInfoEXT callback_info;
+    VkInstance vk_instance = instance->vk_instance;
+    VkDebugReportCallbackEXT callback;
+    VkResult vr;
+
+    callback_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
+    callback_info.pNext = NULL;
+    callback_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
+    callback_info.pfnCallback = vkd3d_debug_report_callback;
+    callback_info.pUserData = NULL;
+    if ((vr = VK_CALL(vkCreateDebugReportCallbackEXT(vk_instance, &callback_info, NULL, &callback)) < 0))
+    {
+        WARN("Failed to create debug report callback, vr %d.\n", vr);
+        return;
+    }
+
+    instance->vk_debug_callback = callback;
+}
+
+static const struct vkd3d_debug_option vkd3d_config_options[] =
+{
+    {"vk_debug", VKD3D_CONFIG_FLAG_VULKAN_DEBUG}, /* enable Vulkan debug extensions */
+};
+
+static uint64_t vkd3d_init_config_flags(void)
+{
+    uint64_t config_flags;
+    const char *config;
+
+    config = getenv("VKD3D_CONFIG");
+    config_flags = vkd3d_parse_debug_options(config, vkd3d_config_options, ARRAY_SIZE(vkd3d_config_options));
+
+    if (config_flags)
+        TRACE("VKD3D_CONFIG='%s'.\n", config);
+
+    return config_flags;
+}
+
+static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance,
+        const struct vkd3d_instance_create_info *create_info)
+{
+    const struct vkd3d_vk_global_procs *vk_global_procs = &instance->vk_global_procs;
+    const struct vkd3d_optional_instance_extensions_info *optional_extensions;
+    const struct vkd3d_application_info *vkd3d_application_info;
+    bool *user_extension_supported = NULL;
+    VkApplicationInfo application_info;
+    VkInstanceCreateInfo instance_info;
+    char application_name[PATH_MAX];
+    uint32_t extension_count;
+    const char **extensions;
+    VkInstance vk_instance;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("Build: " PACKAGE_STRING VKD3D_VCS_ID ".\n");
+
+    if (!create_info->pfn_signal_event)
+    {
+        ERR("Invalid signal event function pointer.\n");
+        return E_INVALIDARG;
+    }
+    if (!create_info->pfn_create_thread != !create_info->pfn_join_thread)
+    {
+        ERR("Invalid create/join thread function pointers.\n");
+        return E_INVALIDARG;
+    }
+    if (create_info->wchar_size != 2 && create_info->wchar_size != 4)
+    {
+        ERR("Unexpected WCHAR size %zu.\n", create_info->wchar_size);
+        return E_INVALIDARG;
+    }
+
+    instance->signal_event = create_info->pfn_signal_event;
+    instance->create_thread = create_info->pfn_create_thread;
+    instance->join_thread = create_info->pfn_join_thread;
+    instance->wchar_size = create_info->wchar_size;
+
+    instance->config_flags = vkd3d_init_config_flags();
+
+    if (FAILED(hr = vkd3d_init_vk_global_procs(instance, create_info->pfn_vkGetInstanceProcAddr)))
+    {
+        ERR("Failed to initialize Vulkan global procs, hr %#x.\n", hr);
+        return hr;
+    }
+
+    if (FAILED(hr = vkd3d_init_instance_caps(instance, create_info,
+            &extension_count, &user_extension_supported)))
+    {
+        if (instance->libvulkan)
+            vkd3d_dlclose(instance->libvulkan);
+        return hr;
+    }
+
+    application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    application_info.pNext = NULL;
+    application_info.pApplicationName = NULL;
+    application_info.applicationVersion = 0;
+    application_info.pEngineName = PACKAGE_NAME;
+    application_info.engineVersion = vkd3d_get_vk_version();
+    application_info.apiVersion = VK_API_VERSION_1_0;
+    instance->api_version = VKD3D_API_VERSION_1_0;
+
+    if ((vkd3d_application_info = vkd3d_find_struct(create_info->next, APPLICATION_INFO)))
+    {
+        if (vkd3d_application_info->application_name)
+            application_info.pApplicationName = vkd3d_application_info->application_name;
+        else if (vkd3d_get_program_name(application_name))
+            application_info.pApplicationName = application_name;
+        application_info.applicationVersion = vkd3d_application_info->application_version;
+        if (vkd3d_application_info->engine_name)
+        {
+            application_info.pEngineName = vkd3d_application_info->engine_name;
+            application_info.engineVersion = vkd3d_application_info->engine_version;
+        }
+        instance->api_version = vkd3d_application_info->api_version;
+    }
+    else if (vkd3d_get_program_name(application_name))
+    {
+        application_info.pApplicationName = application_name;
+    }
+
+    TRACE("Application: %s.\n", debugstr_a(application_info.pApplicationName));
+    TRACE("vkd3d API version: %u.\n", instance->api_version);
+
+    if (!(extensions = vkd3d_calloc(extension_count, sizeof(*extensions))))
+    {
+        if (instance->libvulkan)
+            vkd3d_dlclose(instance->libvulkan);
+        vkd3d_free(user_extension_supported);
+        return E_OUTOFMEMORY;
+    }
+
+    optional_extensions = vkd3d_find_struct(create_info->next, OPTIONAL_INSTANCE_EXTENSIONS_INFO);
+
+    instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    instance_info.pNext = NULL;
+    instance_info.flags = 0;
+    instance_info.pApplicationInfo = &application_info;
+    instance_info.enabledLayerCount = 0;
+    instance_info.ppEnabledLayerNames = NULL;
+    instance_info.enabledExtensionCount = vkd3d_enable_extensions(extensions, NULL, 0,
+            optional_instance_extensions, ARRAY_SIZE(optional_instance_extensions),
+            create_info->instance_extensions, create_info->instance_extension_count,
+            optional_extensions ? optional_extensions->extensions : NULL,
+            optional_extensions ? optional_extensions->extension_count : 0,
+            user_extension_supported, &instance->vk_info);
+    instance_info.ppEnabledExtensionNames = extensions;
+    vkd3d_free(user_extension_supported);
+
+    vr = vk_global_procs->vkCreateInstance(&instance_info, NULL, &vk_instance);
+    vkd3d_free(extensions);
+    if (vr < 0)
+    {
+        ERR("Failed to create Vulkan instance, vr %d.\n", vr);
+        if (instance->libvulkan)
+            vkd3d_dlclose(instance->libvulkan);
+        return hresult_from_vk_result(vr);
+    }
+
+    if (FAILED(hr = vkd3d_load_vk_instance_procs(&instance->vk_procs, vk_global_procs, vk_instance)))
+    {
+        ERR("Failed to load instance procs, hr %#x.\n", hr);
+        if (instance->vk_procs.vkDestroyInstance)
+            instance->vk_procs.vkDestroyInstance(vk_instance, NULL);
+        if (instance->libvulkan)
+            vkd3d_dlclose(instance->libvulkan);
+        return hr;
+    }
+
+    instance->vk_instance = vk_instance;
+
+    TRACE("Created Vulkan instance %p.\n", vk_instance);
+
+    instance->refcount = 1;
+
+    instance->vk_debug_callback = VK_NULL_HANDLE;
+    if (instance->vk_info.EXT_debug_report)
+        vkd3d_init_debug_report(instance);
+
+    return S_OK;
+}
+
+HRESULT vkd3d_create_instance(const struct vkd3d_instance_create_info *create_info,
+        struct vkd3d_instance **instance)
+{
+    struct vkd3d_instance *object;
+    HRESULT hr;
+
+    TRACE("create_info %p, instance %p.\n", create_info, instance);
+
+    if (!create_info || !instance)
+        return E_INVALIDARG;
+    if (create_info->type != VKD3D_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
+    {
+        WARN("Invalid structure type %#x.\n", create_info->type);
+        return E_INVALIDARG;
+    }
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = vkd3d_instance_init(object, create_info)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created instance %p.\n", object);
+
+    *instance = object;
+
+    return S_OK;
+}
+
+static void vkd3d_destroy_instance(struct vkd3d_instance *instance)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &instance->vk_procs;
+    VkInstance vk_instance = instance->vk_instance;
+
+    if (instance->vk_debug_callback)
+        VK_CALL(vkDestroyDebugReportCallbackEXT(vk_instance, instance->vk_debug_callback, NULL));
+
+    VK_CALL(vkDestroyInstance(vk_instance, NULL));
+
+    if (instance->libvulkan)
+        vkd3d_dlclose(instance->libvulkan);
+
+    vkd3d_free(instance);
+}
+
+ULONG vkd3d_instance_incref(struct vkd3d_instance *instance)
+{
+    ULONG refcount = InterlockedIncrement(&instance->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", instance, refcount);
+
+    return refcount;
+}
+
+ULONG vkd3d_instance_decref(struct vkd3d_instance *instance)
+{
+    ULONG refcount = InterlockedDecrement(&instance->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", instance, refcount);
+
+    if (!refcount)
+        vkd3d_destroy_instance(instance);
+
+    return refcount;
+}
+
+VkInstance vkd3d_instance_get_vk_instance(struct vkd3d_instance *instance)
+{
+    return instance->vk_instance;
+}
+
+struct vkd3d_physical_device_info
+{
+    /* properties */
+    VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_properties;
+    VkPhysicalDeviceMaintenance3Properties maintenance3_properties;
+    VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties;
+    VkPhysicalDeviceTransformFeedbackPropertiesEXT xfb_properties;
+    VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_divisor_properties;
+
+    VkPhysicalDeviceProperties2KHR properties2;
+
+    /* features */
+    VkPhysicalDeviceConditionalRenderingFeaturesEXT conditional_rendering_features;
+    VkPhysicalDeviceDepthClipEnableFeaturesEXT depth_clip_features;
+    VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features;
+    VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_features;
+    VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT texel_buffer_alignment_features;
+    VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features;
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
+
+    VkPhysicalDeviceFeatures2 features2;
+};
+
+static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *info, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs;
+    VkPhysicalDeviceConditionalRenderingFeaturesEXT *conditional_rendering_features;
+    VkPhysicalDeviceDescriptorIndexingPropertiesEXT *descriptor_indexing_properties;
+    VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *vertex_divisor_properties;
+    VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment_properties;
+    VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features;
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features;
+    VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
+    VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
+    VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
+    VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
+    VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
+    VkPhysicalDevice physical_device = device->vk_physical_device;
+    VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb_features;
+    struct vkd3d_vulkan_info *vulkan_info = &device->vk_info;
+
+    memset(info, 0, sizeof(*info));
+    conditional_rendering_features = &info->conditional_rendering_features;
+    depth_clip_features = &info->depth_clip_features;
+    descriptor_indexing_features = &info->descriptor_indexing_features;
+    descriptor_indexing_properties = &info->descriptor_indexing_properties;
+    maintenance3_properties = &info->maintenance3_properties;
+    demote_features = &info->demote_features;
+    buffer_alignment_features = &info->texel_buffer_alignment_features;
+    buffer_alignment_properties = &info->texel_buffer_alignment_properties;
+    vertex_divisor_features = &info->vertex_divisor_features;
+    vertex_divisor_properties = &info->vertex_divisor_properties;
+    xfb_features = &info->xfb_features;
+    xfb_properties = &info->xfb_properties;
+
+    info->features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+
+    conditional_rendering_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, conditional_rendering_features);
+    depth_clip_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, depth_clip_features);
+    descriptor_indexing_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, descriptor_indexing_features);
+    demote_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, demote_features);
+    buffer_alignment_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, buffer_alignment_features);
+    xfb_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, xfb_features);
+    vertex_divisor_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+    vk_prepend_struct(&info->features2, vertex_divisor_features);
+
+    if (vulkan_info->KHR_get_physical_device_properties2)
+        VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
+    else
+        VK_CALL(vkGetPhysicalDeviceFeatures(physical_device, &info->features2.features));
+
+    info->properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+
+    maintenance3_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+    vk_prepend_struct(&info->properties2, maintenance3_properties);
+    descriptor_indexing_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
+    vk_prepend_struct(&info->properties2, descriptor_indexing_properties);
+    buffer_alignment_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT;
+    vk_prepend_struct(&info->properties2, buffer_alignment_properties);
+    xfb_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
+    vk_prepend_struct(&info->properties2, xfb_properties);
+    vertex_divisor_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
+    vk_prepend_struct(&info->properties2, vertex_divisor_properties);
+
+    if (vulkan_info->KHR_get_physical_device_properties2)
+        VK_CALL(vkGetPhysicalDeviceProperties2KHR(physical_device, &info->properties2));
+    else
+        VK_CALL(vkGetPhysicalDeviceProperties(physical_device, &info->properties2.properties));
+}
+
+static void vkd3d_trace_physical_device_properties(const VkPhysicalDeviceProperties *properties)
+{
+    const uint32_t driver_version = properties->driverVersion;
+    const uint32_t api_version = properties->apiVersion;
+
+    TRACE("Device name: %s.\n", properties->deviceName);
+    TRACE("Vendor ID: %#x, Device ID: %#x.\n", properties->vendorID, properties->deviceID);
+    TRACE("Driver version: %#x (%u.%u.%u, %u.%u.%u.%u).\n", driver_version,
+            VK_VERSION_MAJOR(driver_version), VK_VERSION_MINOR(driver_version), VK_VERSION_PATCH(driver_version),
+            driver_version >> 22, (driver_version >> 14) & 0xff, (driver_version >> 6) & 0xff, driver_version & 0x3f);
+    TRACE("API version: %u.%u.%u.\n",
+            VK_VERSION_MAJOR(api_version), VK_VERSION_MINOR(api_version), VK_VERSION_PATCH(api_version));
+}
+
+static void vkd3d_trace_physical_device(VkPhysicalDevice device,
+        const struct vkd3d_physical_device_info *info,
+        const struct vkd3d_vk_instance_procs *vk_procs)
+{
+    VkPhysicalDeviceMemoryProperties memory_properties;
+    VkQueueFamilyProperties *queue_properties;
+    unsigned int i, j;
+    uint32_t count;
+
+    vkd3d_trace_physical_device_properties(&info->properties2.properties);
+
+    VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(device, &count, NULL));
+    TRACE("Queue families [%u]:\n", count);
+
+    if (!(queue_properties = vkd3d_calloc(count, sizeof(VkQueueFamilyProperties))))
+        return;
+    VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(device, &count, queue_properties));
+
+    for (i = 0; i < count; ++i)
+    {
+        TRACE(" Queue family [%u]: flags %s, count %u, timestamp bits %u, image transfer granularity %s.\n",
+                i, debug_vk_queue_flags(queue_properties[i].queueFlags),
+                queue_properties[i].queueCount, queue_properties[i].timestampValidBits,
+                debug_vk_extent_3d(queue_properties[i].minImageTransferGranularity));
+    }
+    vkd3d_free(queue_properties);
+
+    VK_CALL(vkGetPhysicalDeviceMemoryProperties(device, &memory_properties));
+    for (i = 0; i < memory_properties.memoryHeapCount; ++i)
+    {
+        const VkMemoryHeap *heap = &memory_properties.memoryHeaps[i];
+        TRACE("Memory heap [%u]: size %#"PRIx64" (%"PRIu64" MiB), flags %s, memory types:\n",
+                i, heap->size, heap->size / 1024 / 1024, debug_vk_memory_heap_flags(heap->flags));
+        for (j = 0; j < memory_properties.memoryTypeCount; ++j)
+        {
+            const VkMemoryType *type = &memory_properties.memoryTypes[j];
+            if (type->heapIndex != i)
+                continue;
+            TRACE("  Memory type [%u]: flags %s.\n", j, debug_vk_memory_property_flags(type->propertyFlags));
+        }
+    }
+}
+
+static void vkd3d_trace_physical_device_limits(const struct vkd3d_physical_device_info *info)
+{
+    const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *divisor_properties;
+    const VkPhysicalDeviceLimits *limits = &info->properties2.properties.limits;
+    const VkPhysicalDeviceDescriptorIndexingPropertiesEXT *descriptor_indexing;
+    const VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment;
+    const VkPhysicalDeviceMaintenance3Properties *maintenance3;
+    const VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb;
+
+    TRACE("Device limits:\n");
+    TRACE("  maxImageDimension1D: %u.\n", limits->maxImageDimension1D);
+    TRACE("  maxImageDimension2D: %u.\n", limits->maxImageDimension2D);
+    TRACE("  maxImageDimension3D: %u.\n", limits->maxImageDimension3D);
+    TRACE("  maxImageDimensionCube: %u.\n", limits->maxImageDimensionCube);
+    TRACE("  maxImageArrayLayers: %u.\n", limits->maxImageArrayLayers);
+    TRACE("  maxTexelBufferElements: %u.\n", limits->maxTexelBufferElements);
+    TRACE("  maxUniformBufferRange: %u.\n", limits->maxUniformBufferRange);
+    TRACE("  maxStorageBufferRange: %u.\n", limits->maxStorageBufferRange);
+    TRACE("  maxPushConstantsSize: %u.\n", limits->maxPushConstantsSize);
+    TRACE("  maxMemoryAllocationCount: %u.\n", limits->maxMemoryAllocationCount);
+    TRACE("  maxSamplerAllocationCount: %u.\n", limits->maxSamplerAllocationCount);
+    TRACE("  bufferImageGranularity: %#"PRIx64".\n", limits->bufferImageGranularity);
+    TRACE("  sparseAddressSpaceSize: %#"PRIx64".\n", limits->sparseAddressSpaceSize);
+    TRACE("  maxBoundDescriptorSets: %u.\n", limits->maxBoundDescriptorSets);
+    TRACE("  maxPerStageDescriptorSamplers: %u.\n", limits->maxPerStageDescriptorSamplers);
+    TRACE("  maxPerStageDescriptorUniformBuffers: %u.\n", limits->maxPerStageDescriptorUniformBuffers);
+    TRACE("  maxPerStageDescriptorStorageBuffers: %u.\n", limits->maxPerStageDescriptorStorageBuffers);
+    TRACE("  maxPerStageDescriptorSampledImages: %u.\n", limits->maxPerStageDescriptorSampledImages);
+    TRACE("  maxPerStageDescriptorStorageImages: %u.\n", limits->maxPerStageDescriptorStorageImages);
+    TRACE("  maxPerStageDescriptorInputAttachments: %u.\n", limits->maxPerStageDescriptorInputAttachments);
+    TRACE("  maxPerStageResources: %u.\n", limits->maxPerStageResources);
+    TRACE("  maxDescriptorSetSamplers: %u.\n", limits->maxDescriptorSetSamplers);
+    TRACE("  maxDescriptorSetUniformBuffers: %u.\n", limits->maxDescriptorSetUniformBuffers);
+    TRACE("  maxDescriptorSetUniformBuffersDynamic: %u.\n", limits->maxDescriptorSetUniformBuffersDynamic);
+    TRACE("  maxDescriptorSetStorageBuffers: %u.\n", limits->maxDescriptorSetStorageBuffers);
+    TRACE("  maxDescriptorSetStorageBuffersDynamic: %u.\n", limits->maxDescriptorSetStorageBuffersDynamic);
+    TRACE("  maxDescriptorSetSampledImages: %u.\n", limits->maxDescriptorSetSampledImages);
+    TRACE("  maxDescriptorSetStorageImages: %u.\n", limits->maxDescriptorSetStorageImages);
+    TRACE("  maxDescriptorSetInputAttachments: %u.\n", limits->maxDescriptorSetInputAttachments);
+    TRACE("  maxVertexInputAttributes: %u.\n", limits->maxVertexInputAttributes);
+    TRACE("  maxVertexInputBindings: %u.\n", limits->maxVertexInputBindings);
+    TRACE("  maxVertexInputAttributeOffset: %u.\n", limits->maxVertexInputAttributeOffset);
+    TRACE("  maxVertexInputBindingStride: %u.\n", limits->maxVertexInputBindingStride);
+    TRACE("  maxVertexOutputComponents: %u.\n", limits->maxVertexOutputComponents);
+    TRACE("  maxTessellationGenerationLevel: %u.\n", limits->maxTessellationGenerationLevel);
+    TRACE("  maxTessellationPatchSize: %u.\n", limits->maxTessellationPatchSize);
+    TRACE("  maxTessellationControlPerVertexInputComponents: %u.\n",
+            limits->maxTessellationControlPerVertexInputComponents);
+    TRACE("  maxTessellationControlPerVertexOutputComponents: %u.\n",
+            limits->maxTessellationControlPerVertexOutputComponents);
+    TRACE("  maxTessellationControlPerPatchOutputComponents: %u.\n",
+            limits->maxTessellationControlPerPatchOutputComponents);
+    TRACE("  maxTessellationControlTotalOutputComponents: %u.\n",
+            limits->maxTessellationControlTotalOutputComponents);
+    TRACE("  maxTessellationEvaluationInputComponents: %u.\n",
+            limits->maxTessellationEvaluationInputComponents);
+    TRACE("  maxTessellationEvaluationOutputComponents: %u.\n",
+            limits->maxTessellationEvaluationOutputComponents);
+    TRACE("  maxGeometryShaderInvocations: %u.\n", limits->maxGeometryShaderInvocations);
+    TRACE("  maxGeometryInputComponents: %u.\n", limits->maxGeometryInputComponents);
+    TRACE("  maxGeometryOutputComponents: %u.\n", limits->maxGeometryOutputComponents);
+    TRACE("  maxGeometryOutputVertices: %u.\n", limits->maxGeometryOutputVertices);
+    TRACE("  maxGeometryTotalOutputComponents: %u.\n", limits->maxGeometryTotalOutputComponents);
+    TRACE("  maxFragmentInputComponents: %u.\n", limits->maxFragmentInputComponents);
+    TRACE("  maxFragmentOutputAttachments: %u.\n", limits->maxFragmentOutputAttachments);
+    TRACE("  maxFragmentDualSrcAttachments: %u.\n", limits->maxFragmentDualSrcAttachments);
+    TRACE("  maxFragmentCombinedOutputResources: %u.\n", limits->maxFragmentCombinedOutputResources);
+    TRACE("  maxComputeSharedMemorySize: %u.\n", limits->maxComputeSharedMemorySize);
+    TRACE("  maxComputeWorkGroupCount: %u, %u, %u.\n", limits->maxComputeWorkGroupCount[0],
+            limits->maxComputeWorkGroupCount[1], limits->maxComputeWorkGroupCount[2]);
+    TRACE("  maxComputeWorkGroupInvocations: %u.\n", limits->maxComputeWorkGroupInvocations);
+    TRACE("  maxComputeWorkGroupSize: %u, %u, %u.\n", limits->maxComputeWorkGroupSize[0],
+            limits->maxComputeWorkGroupSize[1], limits->maxComputeWorkGroupSize[2]);
+    TRACE("  subPixelPrecisionBits: %u.\n", limits->subPixelPrecisionBits);
+    TRACE("  subTexelPrecisionBits: %u.\n", limits->subTexelPrecisionBits);
+    TRACE("  mipmapPrecisionBits: %u.\n", limits->mipmapPrecisionBits);
+    TRACE("  maxDrawIndexedIndexValue: %u.\n", limits->maxDrawIndexedIndexValue);
+    TRACE("  maxDrawIndirectCount: %u.\n", limits->maxDrawIndirectCount);
+    TRACE("  maxSamplerLodBias: %f.\n", limits->maxSamplerLodBias);
+    TRACE("  maxSamplerAnisotropy: %f.\n", limits->maxSamplerAnisotropy);
+    TRACE("  maxViewports: %u.\n", limits->maxViewports);
+    TRACE("  maxViewportDimensions: %u, %u.\n", limits->maxViewportDimensions[0],
+            limits->maxViewportDimensions[1]);
+    TRACE("  viewportBoundsRange: %f, %f.\n", limits->viewportBoundsRange[0], limits->viewportBoundsRange[1]);
+    TRACE("  viewportSubPixelBits: %u.\n", limits->viewportSubPixelBits);
+    TRACE("  minMemoryMapAlignment: %u.\n", (unsigned int)limits->minMemoryMapAlignment);
+    TRACE("  minTexelBufferOffsetAlignment: %#"PRIx64".\n", limits->minTexelBufferOffsetAlignment);
+    TRACE("  minUniformBufferOffsetAlignment: %#"PRIx64".\n", limits->minUniformBufferOffsetAlignment);
+    TRACE("  minStorageBufferOffsetAlignment: %#"PRIx64".\n", limits->minStorageBufferOffsetAlignment);
+    TRACE("  minTexelOffset: %d.\n", limits->minTexelOffset);
+    TRACE("  maxTexelOffset: %u.\n", limits->maxTexelOffset);
+    TRACE("  minTexelGatherOffset: %d.\n", limits->minTexelGatherOffset);
+    TRACE("  maxTexelGatherOffset: %u.\n", limits->maxTexelGatherOffset);
+    TRACE("  minInterpolationOffset: %f.\n", limits->minInterpolationOffset);
+    TRACE("  maxInterpolationOffset: %f.\n", limits->maxInterpolationOffset);
+    TRACE("  subPixelInterpolationOffsetBits: %u.\n", limits->subPixelInterpolationOffsetBits);
+    TRACE("  maxFramebufferWidth: %u.\n", limits->maxFramebufferWidth);
+    TRACE("  maxFramebufferHeight: %u.\n", limits->maxFramebufferHeight);
+    TRACE("  maxFramebufferLayers: %u.\n", limits->maxFramebufferLayers);
+    TRACE("  framebufferColorSampleCounts: %#x.\n", limits->framebufferColorSampleCounts);
+    TRACE("  framebufferDepthSampleCounts: %#x.\n", limits->framebufferDepthSampleCounts);
+    TRACE("  framebufferStencilSampleCounts: %#x.\n", limits->framebufferStencilSampleCounts);
+    TRACE("  framebufferNoAttachmentsSampleCounts: %#x.\n", limits->framebufferNoAttachmentsSampleCounts);
+    TRACE("  maxColorAttachments: %u.\n", limits->maxColorAttachments);
+    TRACE("  sampledImageColorSampleCounts: %#x.\n", limits->sampledImageColorSampleCounts);
+    TRACE("  sampledImageIntegerSampleCounts: %#x.\n", limits->sampledImageIntegerSampleCounts);
+    TRACE("  sampledImageDepthSampleCounts: %#x.\n", limits->sampledImageDepthSampleCounts);
+    TRACE("  sampledImageStencilSampleCounts: %#x.\n", limits->sampledImageStencilSampleCounts);
+    TRACE("  storageImageSampleCounts: %#x.\n", limits->storageImageSampleCounts);
+    TRACE("  maxSampleMaskWords: %u.\n", limits->maxSampleMaskWords);
+    TRACE("  timestampComputeAndGraphics: %#x.\n", limits->timestampComputeAndGraphics);
+    TRACE("  timestampPeriod: %f.\n", limits->timestampPeriod);
+    TRACE("  maxClipDistances: %u.\n", limits->maxClipDistances);
+    TRACE("  maxCullDistances: %u.\n", limits->maxCullDistances);
+    TRACE("  maxCombinedClipAndCullDistances: %u.\n", limits->maxCombinedClipAndCullDistances);
+    TRACE("  discreteQueuePriorities: %u.\n", limits->discreteQueuePriorities);
+    TRACE("  pointSizeRange: %f, %f.\n", limits->pointSizeRange[0], limits->pointSizeRange[1]);
+    TRACE("  lineWidthRange: %f, %f,\n", limits->lineWidthRange[0], limits->lineWidthRange[1]);
+    TRACE("  pointSizeGranularity: %f.\n", limits->pointSizeGranularity);
+    TRACE("  lineWidthGranularity: %f.\n", limits->lineWidthGranularity);
+    TRACE("  strictLines: %#x.\n", limits->strictLines);
+    TRACE("  standardSampleLocations: %#x.\n", limits->standardSampleLocations);
+    TRACE("  optimalBufferCopyOffsetAlignment: %#"PRIx64".\n", limits->optimalBufferCopyOffsetAlignment);
+    TRACE("  optimalBufferCopyRowPitchAlignment: %#"PRIx64".\n", limits->optimalBufferCopyRowPitchAlignment);
+    TRACE("  nonCoherentAtomSize: %#"PRIx64".\n", limits->nonCoherentAtomSize);
+
+    descriptor_indexing = &info->descriptor_indexing_properties;
+    TRACE("  VkPhysicalDeviceDescriptorIndexingPropertiesEXT:\n");
+
+    TRACE("    maxUpdateAfterBindDescriptorsInAllPools: %u.\n",
+            descriptor_indexing->maxUpdateAfterBindDescriptorsInAllPools);
+
+    TRACE("    shaderUniformBufferArrayNonUniformIndexingNative: %#x.\n",
+            descriptor_indexing->shaderUniformBufferArrayNonUniformIndexingNative);
+    TRACE("    shaderSampledImageArrayNonUniformIndexingNative: %#x.\n",
+            descriptor_indexing->shaderSampledImageArrayNonUniformIndexingNative);
+    TRACE("    shaderStorageBufferArrayNonUniformIndexingNative: %#x.\n",
+            descriptor_indexing->shaderStorageBufferArrayNonUniformIndexingNative);
+    TRACE("    shaderStorageImageArrayNonUniformIndexingNative: %#x.\n",
+            descriptor_indexing->shaderStorageImageArrayNonUniformIndexingNative);
+    TRACE("    shaderInputAttachmentArrayNonUniformIndexingNative: %#x.\n",
+            descriptor_indexing->shaderInputAttachmentArrayNonUniformIndexingNative);
+
+    TRACE("    robustBufferAccessUpdateAfterBind: %#x.\n",
+            descriptor_indexing->robustBufferAccessUpdateAfterBind);
+    TRACE("    quadDivergentImplicitLod: %#x.\n",
+            descriptor_indexing->quadDivergentImplicitLod);
+
+    TRACE("    maxPerStageDescriptorUpdateAfterBindSamplers: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindSamplers);
+    TRACE("    maxPerStageDescriptorUpdateAfterBindUniformBuffers: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindUniformBuffers);
+    TRACE("    maxPerStageDescriptorUpdateAfterBindStorageBuffers: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindStorageBuffers);
+    TRACE("    maxPerStageDescriptorUpdateAfterBindSampledImages: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindSampledImages);
+    TRACE("    maxPerStageDescriptorUpdateAfterBindStorageImages: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindStorageImages);
+    TRACE("    maxPerStageDescriptorUpdateAfterBindInputAttachments: %u.\n",
+            descriptor_indexing->maxPerStageDescriptorUpdateAfterBindInputAttachments);
+    TRACE("    maxPerStageUpdateAfterBindResources: %u.\n",
+            descriptor_indexing->maxPerStageUpdateAfterBindResources);
+
+    TRACE("    maxDescriptorSetUpdateAfterBindSamplers: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindSamplers);
+    TRACE("    maxDescriptorSetUpdateAfterBindUniformBuffers: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindUniformBuffers);
+    TRACE("    maxDescriptorSetUpdateAfterBindUniformBuffersDynamic: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
+    TRACE("    maxDescriptorSetUpdateAfterBindStorageBuffers: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindStorageBuffers);
+    TRACE("    maxDescriptorSetUpdateAfterBindStorageBuffersDynamic: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic);
+    TRACE("    maxDescriptorSetUpdateAfterBindSampledImages: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindSampledImages);
+    TRACE("    maxDescriptorSetUpdateAfterBindStorageImages: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindStorageImages);
+    TRACE("    maxDescriptorSetUpdateAfterBindInputAttachments: %u.\n",
+            descriptor_indexing->maxDescriptorSetUpdateAfterBindInputAttachments);
+
+    maintenance3 = &info->maintenance3_properties;
+    TRACE("  VkPhysicalDeviceMaintenance3Properties:\n");
+    TRACE("    maxPerSetDescriptors: %u.\n", maintenance3->maxPerSetDescriptors);
+    TRACE("    maxMemoryAllocationSize: %#"PRIx64".\n", maintenance3->maxMemoryAllocationSize);
+
+    buffer_alignment = &info->texel_buffer_alignment_properties;
+    TRACE("  VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT:\n");
+    TRACE("    storageTexelBufferOffsetAlignmentBytes: %#"PRIx64".\n",
+            buffer_alignment->storageTexelBufferOffsetAlignmentBytes);
+    TRACE("    storageTexelBufferOffsetSingleTexelAlignment: %#x.\n",
+            buffer_alignment->storageTexelBufferOffsetSingleTexelAlignment);
+    TRACE("    uniformTexelBufferOffsetAlignmentBytes: %#"PRIx64".\n",
+            buffer_alignment->uniformTexelBufferOffsetAlignmentBytes);
+    TRACE("    uniformTexelBufferOffsetSingleTexelAlignment: %#x.\n",
+            buffer_alignment->uniformTexelBufferOffsetSingleTexelAlignment);
+
+    xfb = &info->xfb_properties;
+    TRACE("  VkPhysicalDeviceTransformFeedbackPropertiesEXT:\n");
+    TRACE("    maxTransformFeedbackStreams: %u.\n", xfb->maxTransformFeedbackStreams);
+    TRACE("    maxTransformFeedbackBuffers: %u.\n", xfb->maxTransformFeedbackBuffers);
+    TRACE("    maxTransformFeedbackBufferSize: %#"PRIx64".\n", xfb->maxTransformFeedbackBufferSize);
+    TRACE("    maxTransformFeedbackStreamDataSize: %u.\n", xfb->maxTransformFeedbackStreamDataSize);
+    TRACE("    maxTransformFeedbackBufferDataSize: %u.\n", xfb->maxTransformFeedbackBufferDataSize);
+    TRACE("    maxTransformFeedbackBufferDataStride: %u.\n", xfb->maxTransformFeedbackBufferDataStride);
+    TRACE("    transformFeedbackQueries: %#x.\n", xfb->transformFeedbackQueries);
+    TRACE("    transformFeedbackStreamsLinesTriangles: %#x.\n", xfb->transformFeedbackStreamsLinesTriangles);
+    TRACE("    transformFeedbackRasterizationStreamSelect: %#x.\n", xfb->transformFeedbackRasterizationStreamSelect);
+    TRACE("    transformFeedbackDraw: %x.\n", xfb->transformFeedbackDraw);
+
+    divisor_properties = &info->vertex_divisor_properties;
+    TRACE("  VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT:\n");
+    TRACE("    maxVertexAttribDivisor: %u.\n", divisor_properties->maxVertexAttribDivisor);
+}
+
+static void vkd3d_trace_physical_device_features(const struct vkd3d_physical_device_info *info)
+{
+    const VkPhysicalDeviceConditionalRenderingFeaturesEXT *conditional_rendering_features;
+    const VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
+    const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
+    const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *divisor_features;
+    const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing;
+    const VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
+    const VkPhysicalDeviceFeatures *features = &info->features2.features;
+    const VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb;
+
+    TRACE("Device features:\n");
+    TRACE("  robustBufferAccess: %#x.\n", features->robustBufferAccess);
+    TRACE("  fullDrawIndexUint32: %#x.\n", features->fullDrawIndexUint32);
+    TRACE("  imageCubeArray: %#x.\n", features->imageCubeArray);
+    TRACE("  independentBlend: %#x.\n", features->independentBlend);
+    TRACE("  geometryShader: %#x.\n", features->geometryShader);
+    TRACE("  tessellationShader: %#x.\n", features->tessellationShader);
+    TRACE("  sampleRateShading: %#x.\n", features->sampleRateShading);
+    TRACE("  dualSrcBlend: %#x.\n", features->dualSrcBlend);
+    TRACE("  logicOp: %#x.\n", features->logicOp);
+    TRACE("  multiDrawIndirect: %#x.\n", features->multiDrawIndirect);
+    TRACE("  drawIndirectFirstInstance: %#x.\n", features->drawIndirectFirstInstance);
+    TRACE("  depthClamp: %#x.\n", features->depthClamp);
+    TRACE("  depthBiasClamp: %#x.\n", features->depthBiasClamp);
+    TRACE("  fillModeNonSolid: %#x.\n", features->fillModeNonSolid);
+    TRACE("  depthBounds: %#x.\n", features->depthBounds);
+    TRACE("  wideLines: %#x.\n", features->wideLines);
+    TRACE("  largePoints: %#x.\n", features->largePoints);
+    TRACE("  alphaToOne: %#x.\n", features->alphaToOne);
+    TRACE("  multiViewport: %#x.\n", features->multiViewport);
+    TRACE("  samplerAnisotropy: %#x.\n", features->samplerAnisotropy);
+    TRACE("  textureCompressionETC2: %#x.\n", features->textureCompressionETC2);
+    TRACE("  textureCompressionASTC_LDR: %#x.\n", features->textureCompressionASTC_LDR);
+    TRACE("  textureCompressionBC: %#x.\n", features->textureCompressionBC);
+    TRACE("  occlusionQueryPrecise: %#x.\n", features->occlusionQueryPrecise);
+    TRACE("  pipelineStatisticsQuery: %#x.\n", features->pipelineStatisticsQuery);
+    TRACE("  vertexOipelineStoresAndAtomics: %#x.\n", features->vertexPipelineStoresAndAtomics);
+    TRACE("  fragmentStoresAndAtomics: %#x.\n", features->fragmentStoresAndAtomics);
+    TRACE("  shaderTessellationAndGeometryPointSize: %#x.\n", features->shaderTessellationAndGeometryPointSize);
+    TRACE("  shaderImageGatherExtended: %#x.\n", features->shaderImageGatherExtended);
+    TRACE("  shaderStorageImageExtendedFormats: %#x.\n", features->shaderStorageImageExtendedFormats);
+    TRACE("  shaderStorageImageMultisample: %#x.\n", features->shaderStorageImageMultisample);
+    TRACE("  shaderStorageImageReadWithoutFormat: %#x.\n", features->shaderStorageImageReadWithoutFormat);
+    TRACE("  shaderStorageImageWriteWithoutFormat: %#x.\n", features->shaderStorageImageWriteWithoutFormat);
+    TRACE("  shaderUniformBufferArrayDynamicIndexing: %#x.\n", features->shaderUniformBufferArrayDynamicIndexing);
+    TRACE("  shaderSampledImageArrayDynamicIndexing: %#x.\n", features->shaderSampledImageArrayDynamicIndexing);
+    TRACE("  shaderStorageBufferArrayDynamicIndexing: %#x.\n", features->shaderStorageBufferArrayDynamicIndexing);
+    TRACE("  shaderStorageImageArrayDynamicIndexing: %#x.\n", features->shaderStorageImageArrayDynamicIndexing);
+    TRACE("  shaderClipDistance: %#x.\n", features->shaderClipDistance);
+    TRACE("  shaderCullDistance: %#x.\n", features->shaderCullDistance);
+    TRACE("  shaderFloat64: %#x.\n", features->shaderFloat64);
+    TRACE("  shaderInt64: %#x.\n", features->shaderInt64);
+    TRACE("  shaderInt16: %#x.\n", features->shaderInt16);
+    TRACE("  shaderResourceResidency: %#x.\n", features->shaderResourceResidency);
+    TRACE("  shaderResourceMinLod: %#x.\n", features->shaderResourceMinLod);
+    TRACE("  sparseBinding: %#x.\n", features->sparseBinding);
+    TRACE("  sparseResidencyBuffer: %#x.\n", features->sparseResidencyBuffer);
+    TRACE("  sparseResidencyImage2D: %#x.\n", features->sparseResidencyImage2D);
+    TRACE("  sparseResidencyImage3D: %#x.\n", features->sparseResidencyImage3D);
+    TRACE("  sparseResidency2Samples: %#x.\n", features->sparseResidency2Samples);
+    TRACE("  sparseResidency4Samples: %#x.\n", features->sparseResidency4Samples);
+    TRACE("  sparseResidency8Samples: %#x.\n", features->sparseResidency8Samples);
+    TRACE("  sparseResidency16Samples: %#x.\n", features->sparseResidency16Samples);
+    TRACE("  sparseResidencyAliased: %#x.\n", features->sparseResidencyAliased);
+    TRACE("  variableMultisampleRate: %#x.\n", features->variableMultisampleRate);
+    TRACE("  inheritedQueries: %#x.\n", features->inheritedQueries);
+
+    descriptor_indexing = &info->descriptor_indexing_features;
+    TRACE("  VkPhysicalDeviceDescriptorIndexingFeaturesEXT:\n");
+
+    TRACE("    shaderInputAttachmentArrayDynamicIndexing: %#x.\n",
+            descriptor_indexing->shaderInputAttachmentArrayDynamicIndexing);
+    TRACE("    shaderUniformTexelBufferArrayDynamicIndexing: %#x.\n",
+            descriptor_indexing->shaderUniformTexelBufferArrayDynamicIndexing);
+    TRACE("    shaderStorageTexelBufferArrayDynamicIndexing: %#x.\n",
+            descriptor_indexing->shaderStorageTexelBufferArrayDynamicIndexing);
+
+    TRACE("    shaderUniformBufferArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderUniformBufferArrayNonUniformIndexing);
+    TRACE("    shaderSampledImageArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderSampledImageArrayNonUniformIndexing);
+    TRACE("    shaderStorageBufferArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderStorageBufferArrayNonUniformIndexing);
+    TRACE("    shaderStorageImageArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderStorageImageArrayNonUniformIndexing);
+    TRACE("    shaderInputAttachmentArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderInputAttachmentArrayNonUniformIndexing);
+    TRACE("    shaderUniformTexelBufferArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderUniformTexelBufferArrayNonUniformIndexing);
+    TRACE("    shaderStorageTexelBufferArrayNonUniformIndexing: %#x.\n",
+            descriptor_indexing->shaderStorageTexelBufferArrayNonUniformIndexing);
+
+    TRACE("    descriptorBindingUniformBufferUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingUniformBufferUpdateAfterBind);
+    TRACE("    descriptorBindingSampledImageUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingSampledImageUpdateAfterBind);
+    TRACE("    descriptorBindingStorageImageUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingStorageImageUpdateAfterBind);
+    TRACE("    descriptorBindingStorageBufferUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingStorageBufferUpdateAfterBind);
+    TRACE("    descriptorBindingUniformTexelBufferUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingUniformTexelBufferUpdateAfterBind);
+    TRACE("    descriptorBindingStorageTexelBufferUpdateAfterBind: %#x.\n",
+            descriptor_indexing->descriptorBindingStorageTexelBufferUpdateAfterBind);
+
+    TRACE("    descriptorBindingUpdateUnusedWhilePending: %#x.\n",
+            descriptor_indexing->descriptorBindingUpdateUnusedWhilePending);
+    TRACE("    descriptorBindingPartiallyBound: %#x.\n",
+            descriptor_indexing->descriptorBindingPartiallyBound);
+    TRACE("    descriptorBindingVariableDescriptorCount: %#x.\n",
+            descriptor_indexing->descriptorBindingVariableDescriptorCount);
+    TRACE("    runtimeDescriptorArray: %#x.\n",
+            descriptor_indexing->runtimeDescriptorArray);
+
+    conditional_rendering_features = &info->conditional_rendering_features;
+    TRACE("  VkPhysicalDeviceConditionalRenderingFeaturesEXT:\n");
+    TRACE("    conditionalRendering: %#x.\n", conditional_rendering_features->conditionalRendering);
+
+    depth_clip_features = &info->depth_clip_features;
+    TRACE("  VkPhysicalDeviceDepthClipEnableFeaturesEXT:\n");
+    TRACE("    depthClipEnable: %#x.\n", depth_clip_features->depthClipEnable);
+
+    demote_features = &info->demote_features;
+    TRACE("  VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT:\n");
+    TRACE("    shaderDemoteToHelperInvocation: %#x.\n", demote_features->shaderDemoteToHelperInvocation);
+
+    buffer_alignment_features = &info->texel_buffer_alignment_features;
+    TRACE("  VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT:\n");
+    TRACE("    texelBufferAlignment: %#x.\n", buffer_alignment_features->texelBufferAlignment);
+
+    xfb = &info->xfb_features;
+    TRACE("  VkPhysicalDeviceTransformFeedbackFeaturesEXT:\n");
+    TRACE("    transformFeedback: %#x.\n", xfb->transformFeedback);
+    TRACE("    geometryStreams: %#x.\n", xfb->geometryStreams);
+
+    divisor_features = &info->vertex_divisor_features;
+    TRACE("  VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT:\n");
+    TRACE("    vertexAttributeInstanceRateDivisor: %#x.\n",
+            divisor_features->vertexAttributeInstanceRateDivisor);
+    TRACE("    vertexAttributeInstanceRateZeroDivisor: %#x.\n",
+            divisor_features->vertexAttributeInstanceRateZeroDivisor);
+}
+
+static void vkd3d_init_feature_level(struct vkd3d_vulkan_info *vk_info,
+        const VkPhysicalDeviceFeatures *features,
+        const D3D12_FEATURE_DATA_D3D12_OPTIONS *d3d12_options)
+{
+    bool have_11_0 = true;
+
+#define CHECK_MIN_REQUIREMENT(name, value) \
+    if (vk_info->device_limits.name < value) \
+        WARN(#name " does not meet feature level 11_0 requirements.\n");
+#define CHECK_MAX_REQUIREMENT(name, value) \
+    if (vk_info->device_limits.name > value) \
+        WARN(#name " does not meet feature level 11_0 requirements.\n");
+#define CHECK_FEATURE(name) \
+    if (!features->name) \
+    { \
+        WARN(#name " is not supported.\n"); \
+        have_11_0 = false; \
+    }
+
+    if (!vk_info->device_limits.timestampComputeAndGraphics)
+        WARN("Timestamps are not supported on all graphics and compute queues.\n");
+
+    CHECK_MIN_REQUIREMENT(maxPushConstantsSize, D3D12_MAX_ROOT_COST * sizeof(uint32_t));
+    CHECK_MIN_REQUIREMENT(maxComputeSharedMemorySize, D3D12_CS_TGSM_REGISTER_COUNT * sizeof(uint32_t));
+
+    CHECK_MAX_REQUIREMENT(viewportBoundsRange[0], D3D12_VIEWPORT_BOUNDS_MIN);
+    CHECK_MIN_REQUIREMENT(viewportBoundsRange[1], D3D12_VIEWPORT_BOUNDS_MAX);
+    CHECK_MIN_REQUIREMENT(viewportSubPixelBits, 8);
+
+    CHECK_MIN_REQUIREMENT(maxPerStageDescriptorUniformBuffers,
+            D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT);
+
+    CHECK_FEATURE(depthBiasClamp);
+    CHECK_FEATURE(depthClamp);
+    CHECK_FEATURE(drawIndirectFirstInstance);
+    CHECK_FEATURE(dualSrcBlend);
+    CHECK_FEATURE(fragmentStoresAndAtomics);
+    CHECK_FEATURE(fullDrawIndexUint32);
+    CHECK_FEATURE(geometryShader);
+    CHECK_FEATURE(imageCubeArray);
+    CHECK_FEATURE(independentBlend);
+    CHECK_FEATURE(multiDrawIndirect);
+    CHECK_FEATURE(multiViewport);
+    CHECK_FEATURE(occlusionQueryPrecise);
+    CHECK_FEATURE(pipelineStatisticsQuery);
+    CHECK_FEATURE(samplerAnisotropy);
+    CHECK_FEATURE(sampleRateShading);
+    CHECK_FEATURE(shaderClipDistance);
+    CHECK_FEATURE(shaderCullDistance);
+    CHECK_FEATURE(shaderImageGatherExtended);
+    CHECK_FEATURE(shaderStorageImageWriteWithoutFormat);
+    CHECK_FEATURE(tessellationShader);
+
+    if (!vk_info->EXT_depth_clip_enable)
+        WARN("Depth clip enable is not supported.\n");
+    if (!vk_info->EXT_transform_feedback)
+        WARN("Stream output is not supported.\n");
+
+    if (!vk_info->EXT_vertex_attribute_divisor)
+        WARN("Vertex attribute instance rate divisor is not supported.\n");
+    else if (!vk_info->vertex_attrib_zero_divisor)
+        WARN("Vertex attribute instance rate zero divisor is not supported.\n");
+
+#undef CHECK_MIN_REQUIREMENT
+#undef CHECK_MAX_REQUIREMENT
+#undef CHECK_FEATURE
+
+    vk_info->max_feature_level = D3D_FEATURE_LEVEL_11_0;
+
+    if (have_11_0
+            && d3d12_options->OutputMergerLogicOp
+            && features->vertexPipelineStoresAndAtomics
+            && vk_info->device_limits.maxPerStageDescriptorStorageBuffers >= D3D12_UAV_SLOT_COUNT
+            && vk_info->device_limits.maxPerStageDescriptorStorageImages >= D3D12_UAV_SLOT_COUNT)
+        vk_info->max_feature_level = D3D_FEATURE_LEVEL_11_1;
+
+    /* TODO: MinMaxFiltering */
+    if (vk_info->max_feature_level >= D3D_FEATURE_LEVEL_11_1
+            && d3d12_options->TiledResourcesTier >= D3D12_TILED_RESOURCES_TIER_2
+            && d3d12_options->ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_2
+            && d3d12_options->TypedUAVLoadAdditionalFormats)
+        vk_info->max_feature_level = D3D_FEATURE_LEVEL_12_0;
+
+    if (vk_info->max_feature_level >= D3D_FEATURE_LEVEL_12_0
+            && d3d12_options->ROVsSupported
+            && d3d12_options->ConservativeRasterizationTier >= D3D12_CONSERVATIVE_RASTERIZATION_TIER_1)
+        vk_info->max_feature_level = D3D_FEATURE_LEVEL_12_1;
+
+    TRACE("Max feature level: %#x.\n", vk_info->max_feature_level);
+}
+
+static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
+        const struct vkd3d_device_create_info *create_info,
+        struct vkd3d_physical_device_info *physical_device_info,
+        uint32_t *device_extension_count, bool **user_extension_supported)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs;
+    const struct vkd3d_optional_device_extensions_info *optional_extensions;
+    VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing;
+    VkPhysicalDevice physical_device = device->vk_physical_device;
+    struct vkd3d_vulkan_info *vulkan_info = &device->vk_info;
+    VkExtensionProperties *vk_extensions;
+    VkPhysicalDeviceFeatures *features;
+    uint32_t count;
+    VkResult vr;
+
+    *device_extension_count = 0;
+
+    vkd3d_trace_physical_device(physical_device, physical_device_info, vk_procs);
+    vkd3d_trace_physical_device_features(physical_device_info);
+    vkd3d_trace_physical_device_limits(physical_device_info);
+
+    features = &physical_device_info->features2.features;
+
+    if (!features->sparseResidencyBuffer || !features->sparseResidencyImage2D)
+    {
+        features->sparseResidencyBuffer = VK_FALSE;
+        features->sparseResidencyImage2D = VK_FALSE;
+        physical_device_info->properties2.properties.sparseProperties.residencyNonResidentStrict = VK_FALSE;
+    }
+
+    vulkan_info->device_limits = physical_device_info->properties2.properties.limits;
+    vulkan_info->sparse_properties = physical_device_info->properties2.properties.sparseProperties;
+    vulkan_info->rasterization_stream = physical_device_info->xfb_properties.transformFeedbackRasterizationStreamSelect;
+    vulkan_info->transform_feedback_queries = physical_device_info->xfb_properties.transformFeedbackQueries;
+    vulkan_info->max_vertex_attrib_divisor = max(physical_device_info->vertex_divisor_properties.maxVertexAttribDivisor, 1);
+
+    device->feature_options.DoublePrecisionFloatShaderOps = features->shaderFloat64;
+    device->feature_options.OutputMergerLogicOp = features->logicOp;
+    /* SPV_KHR_16bit_storage */
+    device->feature_options.MinPrecisionSupport = D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE;
+
+    if (!features->sparseBinding)
+        device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
+    else if (!device->vk_info.sparse_properties.residencyNonResidentStrict)
+        device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_1;
+    else if (!features->sparseResidencyImage3D)
+        device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_2;
+    else
+        device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_3;
+
+    /* FIXME: Implement tiled resources. */
+    if (device->feature_options.TiledResourcesTier)
+    {
+        WARN("Tiled resources are not implemented yet.\n");
+        device->feature_options.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
+    }
+
+    if (device->vk_info.device_limits.maxPerStageDescriptorSamplers <= 16)
+        device->feature_options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_1;
+    else if (device->vk_info.device_limits.maxPerStageDescriptorUniformBuffers <= 14)
+        device->feature_options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_2;
+    else
+        device->feature_options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_3;
+
+    device->feature_options.PSSpecifiedStencilRefSupported = FALSE;
+    device->feature_options.TypedUAVLoadAdditionalFormats = features->shaderStorageImageExtendedFormats;
+    /* GL_INTEL_fragment_shader_ordering, no Vulkan equivalent. */
+    device->feature_options.ROVsSupported = FALSE;
+    /* GL_INTEL_conservative_rasterization, no Vulkan equivalent. */
+    device->feature_options.ConservativeRasterizationTier = D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED;
+    device->feature_options.MaxGPUVirtualAddressBitsPerResource = 40; /* FIXME */
+    device->feature_options.StandardSwizzle64KBSupported = FALSE;
+    device->feature_options.CrossNodeSharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED;
+    device->feature_options.CrossAdapterRowMajorTextureSupported = FALSE;
+    /* SPV_EXT_shader_viewport_index_layer */
+    device->feature_options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = FALSE;
+    device->feature_options.ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_2;
+
+    /* Shader Model 6 support. */
+    device->feature_options1.WaveOps = FALSE;
+    device->feature_options1.WaveLaneCountMin = 0;
+    device->feature_options1.WaveLaneCountMax = 0;
+    device->feature_options1.TotalLaneCount = 0;
+    device->feature_options1.ExpandedComputeResourceStates = TRUE;
+    device->feature_options1.Int64ShaderOps = features->shaderInt64;
+
+    /* Depth bounds test is enabled in D3D12_DEPTH_STENCIL_DESC1, which is not
+     * supported. */
+    device->feature_options2.DepthBoundsTestSupported = FALSE;
+    /* d3d12_command_list_SetSamplePositions() is not implemented. */
+    device->feature_options2.ProgrammableSamplePositionsTier = D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
+
+    device->feature_options3.CopyQueueTimestampQueriesSupported = FALSE;
+    device->feature_options3.CastingFullyTypedFormatSupported = FALSE;
+    device->feature_options3.WriteBufferImmediateSupportFlags = D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE;
+    device->feature_options3.ViewInstancingTier = D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
+    device->feature_options3.BarycentricsSupported = FALSE;
+
+    device->feature_options4.MSAA64KBAlignedTextureSupported = FALSE;
+    device->feature_options4.SharedResourceCompatibilityTier = D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0;
+    /* An SM 6.2 feature. This would require features->shaderInt16 and
+     * VK_KHR_shader_float16_int8. */
+    device->feature_options4.Native16BitShaderOpsSupported = FALSE;
+
+    device->feature_options5.SRVOnlyTiledResourceTier3 = FALSE;
+    device->feature_options5.RenderPassesTier = D3D12_RENDER_PASS_TIER_0;
+    device->feature_options5.RaytracingTier = D3D12_RAYTRACING_TIER_NOT_SUPPORTED;
+
+    if ((vr = VK_CALL(vkEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL))) < 0)
+    {
+        ERR("Failed to enumerate device extensions, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+    if (!count)
+        return S_OK;
+
+    if (!(vk_extensions = vkd3d_calloc(count, sizeof(*vk_extensions))))
+        return E_OUTOFMEMORY;
+
+    TRACE("Enumerating %u device extensions.\n", count);
+    if ((vr = VK_CALL(vkEnumerateDeviceExtensionProperties(physical_device, NULL, &count, vk_extensions))) < 0)
+    {
+        ERR("Failed to enumerate device extensions, vr %d.\n", vr);
+        vkd3d_free(vk_extensions);
+        return hresult_from_vk_result(vr);
+    }
+
+    optional_extensions = vkd3d_find_struct(create_info->next, OPTIONAL_DEVICE_EXTENSIONS_INFO);
+    if (optional_extensions && optional_extensions->extension_count)
+    {
+        if (!(*user_extension_supported = vkd3d_calloc(optional_extensions->extension_count, sizeof(bool))))
+        {
+            vkd3d_free(vk_extensions);
+            return E_OUTOFMEMORY;
+        }
+    }
+    else
+    {
+        *user_extension_supported = NULL;
+    }
+
+    *device_extension_count = vkd3d_check_extensions(vk_extensions, count,
+            required_device_extensions, ARRAY_SIZE(required_device_extensions),
+            optional_device_extensions, ARRAY_SIZE(optional_device_extensions),
+            create_info->device_extensions, create_info->device_extension_count,
+            optional_extensions ? optional_extensions->extensions : NULL,
+            optional_extensions ? optional_extensions->extension_count : 0,
+            *user_extension_supported, vulkan_info, "device",
+            device->vkd3d_instance->config_flags & VKD3D_CONFIG_FLAG_VULKAN_DEBUG);
+
+    if (!physical_device_info->conditional_rendering_features.conditionalRendering)
+        vulkan_info->EXT_conditional_rendering = false;
+    if (!physical_device_info->depth_clip_features.depthClipEnable)
+        vulkan_info->EXT_depth_clip_enable = false;
+    if (!physical_device_info->demote_features.shaderDemoteToHelperInvocation)
+        vulkan_info->EXT_shader_demote_to_helper_invocation = false;
+    if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment)
+        vulkan_info->EXT_texel_buffer_alignment = false;
+
+    vulkan_info->texel_buffer_alignment_properties = physical_device_info->texel_buffer_alignment_properties;
+
+    if (get_spec_version(vk_extensions, count, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) >= 3)
+    {
+        const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *divisor_features;
+        divisor_features = &physical_device_info->vertex_divisor_features;
+        if (!divisor_features->vertexAttributeInstanceRateDivisor)
+            vulkan_info->EXT_vertex_attribute_divisor = false;
+        vulkan_info->vertex_attrib_zero_divisor = divisor_features->vertexAttributeInstanceRateZeroDivisor;
+    }
+    else
+    {
+        vulkan_info->vertex_attrib_zero_divisor = false;
+    }
+
+    vkd3d_free(vk_extensions);
+
+    vkd3d_init_feature_level(vulkan_info, features, &device->feature_options);
+    if (vulkan_info->max_feature_level < create_info->minimum_feature_level)
+    {
+        WARN("Feature level %#x is not supported.\n", create_info->minimum_feature_level);
+        vkd3d_free(*user_extension_supported);
+        *user_extension_supported = NULL;
+        return E_INVALIDARG;
+    }
+
+    /* Shader extensions. */
+    if (vulkan_info->EXT_shader_demote_to_helper_invocation)
+    {
+        vulkan_info->shader_extension_count = 1;
+        vulkan_info->shader_extensions[0] = VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION;
+    }
+
+    /* Disable unused Vulkan features. */
+    features->shaderTessellationAndGeometryPointSize = VK_FALSE;
+
+    descriptor_indexing = &physical_device_info->descriptor_indexing_features;
+    if (descriptor_indexing)
+    {
+        descriptor_indexing->shaderInputAttachmentArrayDynamicIndexing = VK_FALSE;
+        descriptor_indexing->shaderInputAttachmentArrayNonUniformIndexing = VK_FALSE;
+
+        /* We do not use storage buffers currently. */
+        features->shaderStorageBufferArrayDynamicIndexing = VK_FALSE;
+        descriptor_indexing->shaderStorageBufferArrayNonUniformIndexing = VK_FALSE;
+        descriptor_indexing->descriptorBindingStorageBufferUpdateAfterBind = VK_FALSE;
+    }
+
+    if (vulkan_info->EXT_descriptor_indexing && descriptor_indexing
+            && (descriptor_indexing->descriptorBindingUniformBufferUpdateAfterBind
+            || descriptor_indexing->descriptorBindingStorageBufferUpdateAfterBind
+            || descriptor_indexing->descriptorBindingUniformTexelBufferUpdateAfterBind
+            || descriptor_indexing->descriptorBindingStorageTexelBufferUpdateAfterBind)
+            && !physical_device_info->descriptor_indexing_properties.robustBufferAccessUpdateAfterBind)
+    {
+        WARN("Disabling robust buffer access for the update after bind feature.\n");
+        features->robustBufferAccess = VK_FALSE;
+    }
+
+    return S_OK;
+}
+
+static HRESULT vkd3d_select_physical_device(struct vkd3d_instance *instance,
+        unsigned int device_index, VkPhysicalDevice *selected_device)
+{
+    VkPhysicalDevice dgpu_device = VK_NULL_HANDLE, igpu_device = VK_NULL_HANDLE;
+    const struct vkd3d_vk_instance_procs *vk_procs = &instance->vk_procs;
+    VkInstance vk_instance = instance->vk_instance;
+    VkPhysicalDeviceProperties device_properties;
+    VkPhysicalDevice device = VK_NULL_HANDLE;
+    VkPhysicalDevice *physical_devices;
+    uint32_t count;
+    unsigned int i;
+    VkResult vr;
+
+    count = 0;
+    if ((vr = VK_CALL(vkEnumeratePhysicalDevices(vk_instance, &count, NULL))) < 0)
+    {
+        ERR("Failed to enumerate physical devices, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+    if (!count)
+    {
+        ERR("No physical device available.\n");
+        return E_FAIL;
+    }
+    if (!(physical_devices = vkd3d_calloc(count, sizeof(*physical_devices))))
+        return E_OUTOFMEMORY;
+
+    TRACE("Enumerating %u physical device(s).\n", count);
+    if ((vr = VK_CALL(vkEnumeratePhysicalDevices(vk_instance, &count, physical_devices))) < 0)
+    {
+        ERR("Failed to enumerate physical devices, vr %d.\n", vr);
+        vkd3d_free(physical_devices);
+        return hresult_from_vk_result(vr);
+    }
+
+    if (device_index != ~0u && device_index >= count)
+        WARN("Device index %u is out of range.\n", device_index);
+
+    for (i = 0; i < count; ++i)
+    {
+        VK_CALL(vkGetPhysicalDeviceProperties(physical_devices[i], &device_properties));
+        vkd3d_trace_physical_device_properties(&device_properties);
+
+        if (i == device_index)
+            device = physical_devices[i];
+
+        if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && !dgpu_device)
+            dgpu_device = physical_devices[i];
+        else if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && !igpu_device)
+            igpu_device = physical_devices[i];
+    }
+
+    if (!device)
+        device = dgpu_device ? dgpu_device : igpu_device;
+    if (!device)
+        device = physical_devices[0];
+
+    vkd3d_free(physical_devices);
+
+    VK_CALL(vkGetPhysicalDeviceProperties(device, &device_properties));
+    TRACE("Using device: %s, %#x:%#x.\n", device_properties.deviceName,
+            device_properties.vendorID, device_properties.deviceID);
+
+    *selected_device = device;
+
+    return S_OK;
+}
+
+/* Vulkan queues */
+enum vkd3d_queue_family
+{
+    VKD3D_QUEUE_FAMILY_DIRECT,
+    VKD3D_QUEUE_FAMILY_COMPUTE,
+    VKD3D_QUEUE_FAMILY_TRANSFER,
+
+    VKD3D_QUEUE_FAMILY_COUNT,
+};
+
+struct vkd3d_device_queue_info
+{
+    unsigned int family_index[VKD3D_QUEUE_FAMILY_COUNT];
+    VkQueueFamilyProperties vk_properties[VKD3D_QUEUE_FAMILY_COUNT];
+
+    unsigned int vk_family_count;
+    VkDeviceQueueCreateInfo vk_queue_create_info[VKD3D_QUEUE_FAMILY_COUNT];
+};
+
+static void d3d12_device_destroy_vkd3d_queues(struct d3d12_device *device)
+{
+    if (device->direct_queue)
+        vkd3d_queue_destroy(device->direct_queue, device);
+    if (device->compute_queue && device->compute_queue != device->direct_queue)
+        vkd3d_queue_destroy(device->compute_queue, device);
+    if (device->copy_queue && device->copy_queue != device->direct_queue
+            && device->copy_queue != device->compute_queue)
+        vkd3d_queue_destroy(device->copy_queue, device);
+
+    device->direct_queue = NULL;
+    device->compute_queue = NULL;
+    device->copy_queue = NULL;
+}
+
+static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device,
+        const struct vkd3d_device_queue_info *queue_info)
+{
+    uint32_t transfer_family_index = queue_info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER];
+    uint32_t compute_family_index = queue_info->family_index[VKD3D_QUEUE_FAMILY_COMPUTE];
+    uint32_t direct_family_index = queue_info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
+    HRESULT hr;
+
+    device->direct_queue = NULL;
+    device->compute_queue = NULL;
+    device->copy_queue = NULL;
+
+    device->queue_family_count = 0;
+    memset(device->queue_family_indices, 0, sizeof(device->queue_family_indices));
+
+    if (SUCCEEDED((hr = vkd3d_queue_create(device, direct_family_index,
+            &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT], &device->direct_queue))))
+        device->queue_family_indices[device->queue_family_count++] = direct_family_index;
+    else
+        goto out_destroy_queues;
+
+    if (compute_family_index == direct_family_index)
+        device->compute_queue = device->direct_queue;
+    else if (SUCCEEDED(hr = vkd3d_queue_create(device, compute_family_index,
+            &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_COMPUTE], &device->compute_queue)))
+        device->queue_family_indices[device->queue_family_count++] = compute_family_index;
+    else
+        goto out_destroy_queues;
+
+    if (transfer_family_index == direct_family_index)
+        device->copy_queue = device->direct_queue;
+    else if (transfer_family_index == compute_family_index)
+        device->copy_queue = device->compute_queue;
+    else if (SUCCEEDED(hr = vkd3d_queue_create(device, transfer_family_index,
+            &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER], &device->copy_queue)))
+        device->queue_family_indices[device->queue_family_count++] = transfer_family_index;
+    else
+        goto out_destroy_queues;
+
+    device->feature_options3.CopyQueueTimestampQueriesSupported = !!device->copy_queue->timestamp_bits;
+
+    return S_OK;
+
+out_destroy_queues:
+    d3d12_device_destroy_vkd3d_queues(device);
+    return hr;
+}
+
+static float queue_priorities[] = {1.0f};
+
+static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance,
+        VkPhysicalDevice physical_device, struct vkd3d_device_queue_info *info)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &vkd3d_instance->vk_procs;
+    VkQueueFamilyProperties *queue_properties = NULL;
+    VkDeviceQueueCreateInfo *queue_info = NULL;
+    unsigned int i;
+    uint32_t count;
+
+    memset(info, 0, sizeof(*info));
+    for (i = 0; i < ARRAY_SIZE(info->family_index); ++i)
+        info->family_index[i] = ~0u;
+
+    VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, NULL));
+    if (!(queue_properties = vkd3d_calloc(count, sizeof(*queue_properties))))
+        return E_OUTOFMEMORY;
+    VK_CALL(vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, queue_properties));
+
+    for (i = 0; i < count; ++i)
+    {
+        enum vkd3d_queue_family vkd3d_family = VKD3D_QUEUE_FAMILY_COUNT;
+
+        if ((queue_properties[i].queueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))
+                == (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))
+        {
+            vkd3d_family = VKD3D_QUEUE_FAMILY_DIRECT;
+        }
+        if ((queue_properties[i].queueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))
+                == VK_QUEUE_COMPUTE_BIT)
+        {
+            vkd3d_family = VKD3D_QUEUE_FAMILY_COMPUTE;
+        }
+        if ((queue_properties[i].queueFlags & ~VK_QUEUE_SPARSE_BINDING_BIT) == VK_QUEUE_TRANSFER_BIT)
+        {
+            vkd3d_family = VKD3D_QUEUE_FAMILY_TRANSFER;
+        }
+
+        if (vkd3d_family == VKD3D_QUEUE_FAMILY_COUNT)
+            continue;
+
+        info->family_index[vkd3d_family] = i;
+        info->vk_properties[vkd3d_family] = queue_properties[i];
+        queue_info = &info->vk_queue_create_info[vkd3d_family];
+
+        queue_info->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+        queue_info->pNext = NULL;
+        queue_info->flags = 0;
+        queue_info->queueFamilyIndex = i;
+        queue_info->queueCount = 1; /* FIXME: Use multiple queues. */
+        queue_info->pQueuePriorities = queue_priorities;
+    }
+
+    vkd3d_free(queue_properties);
+
+    if (info->family_index[VKD3D_QUEUE_FAMILY_DIRECT] == ~0u)
+    {
+        FIXME("Could not find a suitable queue family for a direct command queue.\n");
+        return E_FAIL;
+    }
+
+    /* No compute-only queue family, reuse the direct queue family with graphics and compute. */
+    if (info->family_index[VKD3D_QUEUE_FAMILY_COMPUTE] == ~0u)
+    {
+        info->family_index[VKD3D_QUEUE_FAMILY_COMPUTE] = info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
+        info->vk_properties[VKD3D_QUEUE_FAMILY_COMPUTE] = info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT];
+    }
+    if (info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] == ~0u)
+    {
+        info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] = info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
+        info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER] = info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT];
+    }
+
+    /* Compact the array. */
+    info->vk_family_count = 1;
+    for (i = info->vk_family_count; i < ARRAY_SIZE(info->vk_queue_create_info); ++i)
+    {
+        if (info->vk_queue_create_info[i].queueCount)
+            info->vk_queue_create_info[info->vk_family_count++] = info->vk_queue_create_info[i];
+    }
+
+    return S_OK;
+}
+
+/* The 4 MiB alignment requirement for MSAA resources was lowered to 64KB on
+ * hardware that supports it. This is distinct from the small MSAA requirement
+ * which applies to resources of a total size of 4 MiB or less. */
+static bool d3d12_is_64k_msaa_supported(struct d3d12_device *device)
+{
+    D3D12_RESOURCE_ALLOCATION_INFO info;
+    D3D12_RESOURCE_DESC resource_desc;
+
+    memset(&resource_desc, 0, sizeof(resource_desc));
+    resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+    resource_desc.Width = 1024;
+    resource_desc.Height = 1025;
+    resource_desc.DepthOrArraySize = 1;
+    resource_desc.MipLevels = 1;
+    resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    resource_desc.SampleDesc.Count = 4;
+    resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
+
+    /* FIXME: in some cases Vulkan requires 0x20000 or more for non-MSAA
+     * resources, which must have 0x10000 in their description, so we might
+     * reasonably return true here for 0x20000 or 0x40000. */
+    return SUCCEEDED(vkd3d_get_image_allocation_info(device, &resource_desc, &info))
+            && info.Alignment <= 0x10000;
+}
+
+static HRESULT vkd3d_create_vk_device(struct d3d12_device *device,
+        const struct vkd3d_device_create_info *create_info)
+{
+    const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs;
+    const struct vkd3d_optional_device_extensions_info *optional_extensions;
+    struct vkd3d_physical_device_info physical_device_info;
+    struct vkd3d_device_queue_info device_queue_info;
+    bool *user_extension_supported = NULL;
+    VkPhysicalDevice physical_device;
+    VkDeviceCreateInfo device_info;
+    unsigned int device_index;
+    uint32_t extension_count;
+    const char **extensions;
+    VkDevice vk_device;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("device %p, create_info %p.\n", device, create_info);
+
+    physical_device = create_info->vk_physical_device;
+    device_index = vkd3d_env_var_as_uint("VKD3D_VULKAN_DEVICE", ~0u);
+    if ((!physical_device || device_index != ~0u)
+            && FAILED(hr = vkd3d_select_physical_device(device->vkd3d_instance, device_index, &physical_device)))
+        return hr;
+
+    device->vk_physical_device = physical_device;
+
+    if (FAILED(hr = vkd3d_select_queues(device->vkd3d_instance, physical_device, &device_queue_info)))
+        return hr;
+
+    TRACE("Using queue family %u for direct command queues.\n",
+            device_queue_info.family_index[VKD3D_QUEUE_FAMILY_DIRECT]);
+    TRACE("Using queue family %u for compute command queues.\n",
+            device_queue_info.family_index[VKD3D_QUEUE_FAMILY_COMPUTE]);
+    TRACE("Using queue family %u for copy command queues.\n",
+            device_queue_info.family_index[VKD3D_QUEUE_FAMILY_TRANSFER]);
+
+    VK_CALL(vkGetPhysicalDeviceMemoryProperties(physical_device, &device->memory_properties));
+
+    vkd3d_physical_device_info_init(&physical_device_info, device);
+
+    if (FAILED(hr = vkd3d_init_device_caps(device, create_info, &physical_device_info,
+            &extension_count, &user_extension_supported)))
+        return hr;
+
+    if (!(extensions = vkd3d_calloc(extension_count, sizeof(*extensions))))
+    {
+        vkd3d_free(user_extension_supported);
+        return E_OUTOFMEMORY;
+    }
+
+    optional_extensions = vkd3d_find_struct(create_info->next, OPTIONAL_DEVICE_EXTENSIONS_INFO);
+
+    /* Create device */
+    device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+    device_info.pNext = physical_device_info.features2.pNext;
+    device_info.flags = 0;
+    device_info.queueCreateInfoCount = device_queue_info.vk_family_count;
+    device_info.pQueueCreateInfos = device_queue_info.vk_queue_create_info;
+    device_info.enabledLayerCount = 0;
+    device_info.ppEnabledLayerNames = NULL;
+    device_info.enabledExtensionCount = vkd3d_enable_extensions(extensions,
+            required_device_extensions, ARRAY_SIZE(required_device_extensions),
+            optional_device_extensions, ARRAY_SIZE(optional_device_extensions),
+            create_info->device_extensions, create_info->device_extension_count,
+            optional_extensions ? optional_extensions->extensions : NULL,
+            optional_extensions ? optional_extensions->extension_count : 0,
+            user_extension_supported, &device->vk_info);
+    device_info.ppEnabledExtensionNames = extensions;
+    device_info.pEnabledFeatures = &physical_device_info.features2.features;
+    vkd3d_free(user_extension_supported);
+
+    vr = VK_CALL(vkCreateDevice(physical_device, &device_info, NULL, &vk_device));
+    vkd3d_free(extensions);
+    if (vr < 0)
+    {
+        ERR("Failed to create Vulkan device, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    if (FAILED(hr = vkd3d_load_vk_device_procs(&device->vk_procs, vk_procs, vk_device)))
+    {
+        ERR("Failed to load device procs, hr %#x.\n", hr);
+        if (device->vk_procs.vkDestroyDevice)
+            device->vk_procs.vkDestroyDevice(vk_device, NULL);
+        return hr;
+    }
+
+    device->vk_device = vk_device;
+
+    if (FAILED(hr = d3d12_device_create_vkd3d_queues(device, &device_queue_info)))
+    {
+        ERR("Failed to create queues, hr %#x.\n", hr);
+        device->vk_procs.vkDestroyDevice(vk_device, NULL);
+        return hr;
+    }
+
+    device->feature_options4.MSAA64KBAlignedTextureSupported = d3d12_is_64k_msaa_supported(device);
+
+    TRACE("Created Vulkan device %p.\n", vk_device);
+
+    return hr;
+}
+
+static HRESULT d3d12_device_init_pipeline_cache(struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkPipelineCacheCreateInfo cache_info;
+    VkResult vr;
+    int rc;
+
+    if ((rc = pthread_mutex_init(&device->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+    cache_info.pNext = NULL;
+    cache_info.flags = 0;
+    cache_info.initialDataSize = 0;
+    cache_info.pInitialData = NULL;
+    if ((vr = VK_CALL(vkCreatePipelineCache(device->vk_device, &cache_info, NULL,
+            &device->vk_pipeline_cache))) < 0)
+    {
+        ERR("Failed to create Vulkan pipeline cache, vr %d.\n", vr);
+        device->vk_pipeline_cache = VK_NULL_HANDLE;
+    }
+
+    return S_OK;
+}
+
+static void d3d12_device_destroy_pipeline_cache(struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    if (device->vk_pipeline_cache)
+        VK_CALL(vkDestroyPipelineCache(device->vk_device, device->vk_pipeline_cache, NULL));
+
+    pthread_mutex_destroy(&device->mutex);
+}
+
+#define VKD3D_VA_FALLBACK_BASE      0x8000000000000000ull
+#define VKD3D_VA_SLAB_BASE          0x0000001000000000ull
+#define VKD3D_VA_SLAB_SIZE_SHIFT    32
+#define VKD3D_VA_SLAB_SIZE          (1ull << VKD3D_VA_SLAB_SIZE_SHIFT)
+#define VKD3D_VA_SLAB_COUNT         (64 * 1024)
+
+static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_slab(struct vkd3d_gpu_va_allocator *allocator,
+        size_t aligned_size, void *ptr)
+{
+    struct vkd3d_gpu_va_slab *slab;
+    D3D12_GPU_VIRTUAL_ADDRESS address;
+    unsigned slab_idx;
+
+    slab = allocator->free_slab;
+    allocator->free_slab = slab->ptr;
+    slab->size = aligned_size;
+    slab->ptr = ptr;
+
+    /* It is critical that the multiplication happens in 64-bit to not
+     * overflow. */
+    slab_idx = slab - allocator->slabs;
+    address = VKD3D_VA_SLAB_BASE + slab_idx * VKD3D_VA_SLAB_SIZE;
+
+    TRACE("Allocated address %#"PRIx64", slab %u, size %zu.\n", address, slab_idx, aligned_size);
+
+    return address;
+}
+
+static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_fallback(struct vkd3d_gpu_va_allocator *allocator,
+        size_t alignment, size_t aligned_size, void *ptr)
+{
+    struct vkd3d_gpu_va_allocation *allocation;
+    D3D12_GPU_VIRTUAL_ADDRESS base, ceiling;
+
+    base = allocator->fallback_floor;
+    ceiling = ~(D3D12_GPU_VIRTUAL_ADDRESS)0;
+    ceiling -= alignment - 1;
+    if (aligned_size > ceiling || ceiling - aligned_size < base)
+        return 0;
+
+    base = (base + (alignment - 1)) & ~((D3D12_GPU_VIRTUAL_ADDRESS)alignment - 1);
+
+    if (!vkd3d_array_reserve((void **)&allocator->fallback_allocations, &allocator->fallback_allocations_size,
+            allocator->fallback_allocation_count + 1, sizeof(*allocator->fallback_allocations)))
+        return 0;
+
+    allocation = &allocator->fallback_allocations[allocator->fallback_allocation_count++];
+    allocation->base = base;
+    allocation->size = aligned_size;
+    allocation->ptr = ptr;
+
+    /* This pointer is bumped and never lowered on a free. However, this will
+     * only fail once we have exhausted 63 bits of address space. */
+    allocator->fallback_floor = base + aligned_size;
+
+    TRACE("Allocated address %#"PRIx64", size %zu.\n", base, aligned_size);
+
+    return base;
+}
+
+D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
+        size_t alignment, size_t size, void *ptr)
+{
+    D3D12_GPU_VIRTUAL_ADDRESS address;
+    int rc;
+
+    if (size > ~(size_t)0 - (alignment - 1))
+        return 0;
+    size = align(size, alignment);
+
+    if ((rc = pthread_mutex_lock(&allocator->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return 0;
+    }
+
+    if (size <= VKD3D_VA_SLAB_SIZE && allocator->free_slab)
+        address = vkd3d_gpu_va_allocator_allocate_slab(allocator, size, ptr);
+    else
+        address = vkd3d_gpu_va_allocator_allocate_fallback(allocator, alignment, size, ptr);
+
+    pthread_mutex_unlock(&allocator->mutex);
+
+    return address;
+}
+
+static void *vkd3d_gpu_va_allocator_dereference_slab(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    const struct vkd3d_gpu_va_slab *slab;
+    D3D12_GPU_VIRTUAL_ADDRESS base_offset;
+    unsigned int slab_idx;
+
+    base_offset = address - VKD3D_VA_SLAB_BASE;
+    slab_idx = base_offset >> VKD3D_VA_SLAB_SIZE_SHIFT;
+
+    if (slab_idx >= VKD3D_VA_SLAB_COUNT)
+    {
+        ERR("Invalid slab index %u for address %#"PRIx64".\n", slab_idx, address);
+        return NULL;
+    }
+
+    slab = &allocator->slabs[slab_idx];
+    base_offset -= slab_idx * VKD3D_VA_SLAB_SIZE;
+    if (base_offset >= slab->size)
+    {
+        ERR("Address %#"PRIx64" is %#"PRIx64" bytes into slab %u of size %zu.\n",
+                address, base_offset, slab_idx, slab->size);
+        return NULL;
+    }
+    return slab->ptr;
+}
+
+static int vkd3d_gpu_va_allocation_compare(const void *k, const void *e)
+{
+    const struct vkd3d_gpu_va_allocation *allocation = e;
+    const D3D12_GPU_VIRTUAL_ADDRESS *address = k;
+
+    if (*address < allocation->base)
+        return -1;
+    if (*address - allocation->base >= allocation->size)
+        return 1;
+    return 0;
+}
+
+static void *vkd3d_gpu_va_allocator_dereference_fallback(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct vkd3d_gpu_va_allocation *allocation;
+
+    allocation = bsearch(&address, allocator->fallback_allocations, allocator->fallback_allocation_count,
+            sizeof(*allocation), vkd3d_gpu_va_allocation_compare);
+
+    return allocation ? allocation->ptr : NULL;
+}
+
+void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    void *ret;
+    int rc;
+
+    /* If we land in the non-fallback region, dereferencing VA is lock-less.
+     * The base pointer is immutable, and the only way we can have a data race
+     * is if some other thread is poking into the
+     * slab_mem_allocation[base_index] block. This can only happen if someone
+     * is trying to free the entry while we're dereferencing it, which would
+     * be a serious application bug. */
+    if (address < VKD3D_VA_FALLBACK_BASE)
+        return vkd3d_gpu_va_allocator_dereference_slab(allocator, address);
+
+    /* Slow fallback. */
+    if ((rc = pthread_mutex_lock(&allocator->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return NULL;
+    }
+
+    ret = vkd3d_gpu_va_allocator_dereference_fallback(allocator, address);
+
+    pthread_mutex_unlock(&allocator->mutex);
+
+    return ret;
+}
+
+static void vkd3d_gpu_va_allocator_free_slab(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    D3D12_GPU_VIRTUAL_ADDRESS base_offset;
+    struct vkd3d_gpu_va_slab *slab;
+    unsigned int slab_idx;
+
+    base_offset = address - VKD3D_VA_SLAB_BASE;
+    slab_idx = base_offset >> VKD3D_VA_SLAB_SIZE_SHIFT;
+
+    if (slab_idx >= VKD3D_VA_SLAB_COUNT)
+    {
+        ERR("Invalid slab index %u for address %#"PRIx64".\n", slab_idx, address);
+        return;
+    }
+
+    TRACE("Freeing address %#"PRIx64", slab %u.\n", address, slab_idx);
+
+    slab = &allocator->slabs[slab_idx];
+    slab->size = 0;
+    slab->ptr = allocator->free_slab;
+    allocator->free_slab = slab;
+}
+
+static void vkd3d_gpu_va_allocator_free_fallback(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    struct vkd3d_gpu_va_allocation *allocation;
+    unsigned int index;
+
+    allocation = bsearch(&address, allocator->fallback_allocations, allocator->fallback_allocation_count,
+            sizeof(*allocation), vkd3d_gpu_va_allocation_compare);
+
+    if (!allocation || allocation->base != address)
+    {
+        ERR("Address %#"PRIx64" does not match any allocation.\n", address);
+        return;
+    }
+
+    index = allocation - allocator->fallback_allocations;
+    --allocator->fallback_allocation_count;
+    if (index != allocator->fallback_allocation_count)
+        memmove(&allocator->fallback_allocations[index], &allocator->fallback_allocations[index + 1],
+                (allocator->fallback_allocation_count - index) * sizeof(*allocation));
+}
+
+void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&allocator->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    if (address < VKD3D_VA_FALLBACK_BASE)
+    {
+        vkd3d_gpu_va_allocator_free_slab(allocator, address);
+        pthread_mutex_unlock(&allocator->mutex);
+        return;
+    }
+
+    vkd3d_gpu_va_allocator_free_fallback(allocator, address);
+
+    pthread_mutex_unlock(&allocator->mutex);
+}
+
+static bool vkd3d_gpu_va_allocator_init(struct vkd3d_gpu_va_allocator *allocator)
+{
+    unsigned int i;
+    int rc;
+
+    memset(allocator, 0, sizeof(*allocator));
+    allocator->fallback_floor = VKD3D_VA_FALLBACK_BASE;
+
+    /* To remain lock-less, we cannot grow the slabs array after the fact. If
+     * we commit to a maximum number of allocations here, we can dereference
+     * without taking a lock as the base pointer never changes. We would be
+     * able to grow more seamlessly using an array of pointers, but that would
+     * make dereferencing slightly less efficient. */
+    if (!(allocator->slabs = vkd3d_calloc(VKD3D_VA_SLAB_COUNT, sizeof(*allocator->slabs))))
+        return false;
+
+    /* Mark all slabs as free. */
+    allocator->free_slab = &allocator->slabs[0];
+    for (i = 0; i < VKD3D_VA_SLAB_COUNT - 1; ++i)
+    {
+        allocator->slabs[i].ptr = &allocator->slabs[i + 1];
+    }
+
+    if ((rc = pthread_mutex_init(&allocator->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        vkd3d_free(allocator->slabs);
+        return false;
+    }
+
+    return true;
+}
+
+static void vkd3d_gpu_va_allocator_cleanup(struct vkd3d_gpu_va_allocator *allocator)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&allocator->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+    vkd3d_free(allocator->slabs);
+    vkd3d_free(allocator->fallback_allocations);
+    pthread_mutex_unlock(&allocator->mutex);
+    pthread_mutex_destroy(&allocator->mutex);
+}
+
+/* ID3D12Device */
+static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_device, ID3D12Device_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(ID3D12Device *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12Device)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12Device_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_device_AddRef(ID3D12Device *iface)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    ULONG refcount = InterlockedIncrement(&device->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", device, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    ULONG refcount = InterlockedDecrement(&device->refcount);
+    size_t i;
+
+    TRACE("%p decreasing refcount to %u.\n", device, refcount);
+
+    if (!refcount)
+    {
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        vkd3d_private_store_destroy(&device->private_store);
+
+        vkd3d_cleanup_format_info(device);
+        vkd3d_uav_clear_state_cleanup(&device->uav_clear_state, device);
+        vkd3d_destroy_null_resources(&device->null_resources, device);
+        vkd3d_gpu_va_allocator_cleanup(&device->gpu_va_allocator);
+        vkd3d_render_pass_cache_cleanup(&device->render_pass_cache, device);
+        vkd3d_fence_worker_stop(&device->fence_worker, device);
+        d3d12_device_destroy_pipeline_cache(device);
+        d3d12_device_destroy_vkd3d_queues(device);
+        for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i)
+            pthread_mutex_destroy(&device->desc_mutex[i]);
+        VK_CALL(vkDestroyDevice(device->vk_device, NULL));
+        if (device->parent)
+            IUnknown_Release(device->parent);
+        vkd3d_instance_decref(device->vkd3d_instance);
+
+        vkd3d_free(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_GetPrivateData(ID3D12Device *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n",
+            iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&device->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateData(ID3D12Device *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n",
+            iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&device->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateDataInterface(ID3D12Device *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&device->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetName(ID3D12Device *iface, const WCHAR *name)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, device->wchar_size));
+
+    return vkd3d_set_vk_object_name(device, (uint64_t)(uintptr_t)device->vk_device,
+            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, name);
+}
+
+static UINT STDMETHODCALLTYPE d3d12_device_GetNodeCount(ID3D12Device *iface)
+{
+    TRACE("iface %p.\n", iface);
+
+    return 1;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandQueue(ID3D12Device *iface,
+        const D3D12_COMMAND_QUEUE_DESC *desc, REFIID riid, void **command_queue)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_command_queue *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, riid %s, command_queue %p.\n",
+            iface, desc, debugstr_guid(riid), command_queue);
+
+    if (FAILED(hr = d3d12_command_queue_create(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12CommandQueue_iface, &IID_ID3D12CommandQueue,
+            riid, command_queue);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandAllocator(ID3D12Device *iface,
+        D3D12_COMMAND_LIST_TYPE type, REFIID riid, void **command_allocator)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_command_allocator *object;
+    HRESULT hr;
+
+    TRACE("iface %p, type %#x, riid %s, command_allocator %p.\n",
+            iface, type, debugstr_guid(riid), command_allocator);
+
+    if (FAILED(hr = d3d12_command_allocator_create(device, type, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12CommandAllocator_iface, &IID_ID3D12CommandAllocator,
+            riid, command_allocator);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12Device *iface,
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_pipeline_state *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, riid %s, pipeline_state %p.\n",
+            iface, desc, debugstr_guid(riid), pipeline_state);
+
+    if (FAILED(hr = d3d12_pipeline_state_create_graphics(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12PipelineState_iface,
+            &IID_ID3D12PipelineState, riid, pipeline_state);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateComputePipelineState(ID3D12Device *iface,
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_pipeline_state *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, riid %s, pipeline_state %p.\n",
+            iface, desc, debugstr_guid(riid), pipeline_state);
+
+    if (FAILED(hr = d3d12_pipeline_state_create_compute(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12PipelineState_iface,
+            &IID_ID3D12PipelineState, riid, pipeline_state);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device *iface,
+        UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *command_allocator,
+        ID3D12PipelineState *initial_pipeline_state, REFIID riid, void **command_list)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_command_list *object;
+    HRESULT hr;
+
+    TRACE("iface %p, node_mask 0x%08x, type %#x, command_allocator %p, "
+            "initial_pipeline_state %p, riid %s, command_list %p.\n",
+            iface, node_mask, type, command_allocator,
+            initial_pipeline_state, debugstr_guid(riid), command_list);
+
+    if (FAILED(hr = d3d12_command_list_create(device, node_mask, type, command_allocator,
+            initial_pipeline_state, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12GraphicsCommandList2_iface,
+            &IID_ID3D12GraphicsCommandList2, riid, command_list);
+}
+
+/* Direct3D feature levels restrict which formats can be optionally supported. */
+static void vkd3d_restrict_format_support_for_feature_level(D3D12_FEATURE_DATA_FORMAT_SUPPORT *format_support)
+{
+    static const D3D12_FEATURE_DATA_FORMAT_SUPPORT blacklisted_format_features[] =
+    {
+        {DXGI_FORMAT_B8G8R8A8_TYPELESS, D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW,
+                D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE},
+        {DXGI_FORMAT_B8G8R8A8_UNORM,    D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW,
+                D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE},
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(blacklisted_format_features); ++i)
+    {
+        if (blacklisted_format_features[i].Format == format_support->Format)
+        {
+            format_support->Support1 &= ~blacklisted_format_features[i].Support1;
+            format_support->Support2 &= ~blacklisted_format_features[i].Support2;
+            break;
+        }
+    }
+}
+
+static HRESULT d3d12_device_check_multisample_quality_levels(struct d3d12_device *device,
+        D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS *data)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkImageFormatProperties vk_properties;
+    const struct vkd3d_format *format;
+    VkSampleCountFlagBits vk_samples;
+    VkImageUsageFlags vk_usage = 0;
+    VkResult vr;
+
+    TRACE("Format %#x, sample count %u, flags %#x.\n", data->Format, data->SampleCount, data->Flags);
+
+    data->NumQualityLevels = 0;
+
+    if (!(vk_samples = vk_samples_from_sample_count(data->SampleCount)))
+        WARN("Invalid sample count %u.\n", data->SampleCount);
+    if (!data->SampleCount)
+        return E_FAIL;
+
+    if (data->SampleCount == 1)
+    {
+        data->NumQualityLevels = 1;
+        goto done;
+    }
+
+    if (data->Format == DXGI_FORMAT_UNKNOWN)
+        goto done;
+
+    if (!(format = vkd3d_get_format(device, data->Format, false)))
+        format = vkd3d_get_format(device, data->Format, true);
+    if (!format)
+    {
+        FIXME("Unhandled format %#x.\n", data->Format);
+        return E_INVALIDARG;
+    }
+    if (data->Flags)
+        FIXME("Ignoring flags %#x.\n", data->Flags);
+
+    if (format->vk_aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT)
+        vk_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    else
+        vk_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+    vr = VK_CALL(vkGetPhysicalDeviceImageFormatProperties(device->vk_physical_device,
+            format->vk_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, vk_usage, 0, &vk_properties));
+    if (vr == VK_ERROR_FORMAT_NOT_SUPPORTED)
+    {
+        WARN("Format %#x is not supported.\n", format->dxgi_format);
+        goto done;
+    }
+    if (vr < 0)
+    {
+        ERR("Failed to get image format properties, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    if (vk_properties.sampleCounts & vk_samples)
+        data->NumQualityLevels = 1;
+
+done:
+    TRACE("Returning %u quality levels.\n", data->NumQualityLevels);
+    return S_OK;
+}
+
+bool d3d12_device_is_uma(struct d3d12_device *device, bool *coherent)
+{
+    unsigned int i;
+
+    if (coherent)
+        *coherent = true;
+
+    for (i = 0; i < device->memory_properties.memoryTypeCount; ++i)
+    {
+        if (!(device->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
+            return false;
+        if (coherent && !(device->memory_properties.memoryTypes[i].propertyFlags
+                & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+            *coherent = false;
+    }
+
+    return true;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(ID3D12Device *iface,
+        D3D12_FEATURE feature, void *feature_data, UINT feature_data_size)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, feature %#x, feature_data %p, feature_data_size %u.\n",
+            iface, feature, feature_data, feature_data_size);
+
+    switch (feature)
+    {
+        case D3D12_FEATURE_D3D12_OPTIONS:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options;
+
+            TRACE("Double precision shader ops %#x.\n", data->DoublePrecisionFloatShaderOps);
+            TRACE("Output merger logic op %#x.\n", data->OutputMergerLogicOp);
+            TRACE("Shader min precision support %#x.\n", data->MinPrecisionSupport);
+            TRACE("Tiled resources tier %#x.\n", data->TiledResourcesTier);
+            TRACE("Resource binding tier %#x.\n", data->ResourceBindingTier);
+            TRACE("PS specified stencil ref %#x.\n", data->PSSpecifiedStencilRefSupported);
+            TRACE("Typed UAV load and additional formats %#x.\n", data->TypedUAVLoadAdditionalFormats);
+            TRACE("ROV %#x.\n", data->ROVsSupported);
+            TRACE("Conservative rasterization tier %#x.\n", data->ConservativeRasterizationTier);
+            TRACE("Max GPU virtual address bits per resource %u.\n", data->MaxGPUVirtualAddressBitsPerResource);
+            TRACE("Standard swizzle 64KB %#x.\n", data->StandardSwizzle64KBSupported);
+            TRACE("Cross-node sharing tier %#x.\n", data->CrossNodeSharingTier);
+            TRACE("Cross-adapter row-major texture %#x.\n", data->CrossAdapterRowMajorTextureSupported);
+            TRACE("VP and RT array index from any shader without GS emulation %#x.\n",
+                    data->VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation);
+            TRACE("Resource heap tier %#x.\n", data->ResourceHeapTier);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_ARCHITECTURE:
+        {
+            D3D12_FEATURE_DATA_ARCHITECTURE *data = feature_data;
+            bool coherent;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            if (data->NodeIndex)
+            {
+                FIXME("Multi-adapter not supported.\n");
+                return E_INVALIDARG;
+            }
+
+            WARN("Assuming device does not support tile based rendering.\n");
+            data->TileBasedRenderer = FALSE;
+
+            data->UMA = d3d12_device_is_uma(device, &coherent);
+            data->CacheCoherentUMA = data->UMA && coherent;
+
+            TRACE("Tile based renderer %#x, UMA %#x, cache coherent UMA %#x.\n",
+                    data->TileBasedRenderer, data->UMA, data->CacheCoherentUMA);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_FEATURE_LEVELS:
+        {
+            struct vkd3d_vulkan_info *vulkan_info = &device->vk_info;
+            D3D12_FEATURE_DATA_FEATURE_LEVELS *data = feature_data;
+            unsigned int i;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+            if (!data->NumFeatureLevels)
+                return E_INVALIDARG;
+
+            data->MaxSupportedFeatureLevel = 0;
+            for (i = 0; i < data->NumFeatureLevels; ++i)
+            {
+                D3D_FEATURE_LEVEL fl = data->pFeatureLevelsRequested[i];
+                if (data->MaxSupportedFeatureLevel < fl && fl <= vulkan_info->max_feature_level)
+                    data->MaxSupportedFeatureLevel = fl;
+            }
+
+            TRACE("Max supported feature level %#x.\n", data->MaxSupportedFeatureLevel);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_FORMAT_SUPPORT:
+        {
+            const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+            D3D12_FEATURE_DATA_FORMAT_SUPPORT *data = feature_data;
+            VkFormatFeatureFlagBits image_features;
+            const struct vkd3d_format *format;
+            VkFormatProperties properties;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            data->Support1 = D3D12_FORMAT_SUPPORT1_NONE;
+            data->Support2 = D3D12_FORMAT_SUPPORT2_NONE;
+            if (!(format = vkd3d_get_format(device, data->Format, false)))
+                format = vkd3d_get_format(device, data->Format, true);
+            if (!format)
+            {
+                FIXME("Unhandled format %#x.\n", data->Format);
+                return E_INVALIDARG;
+            }
+
+            VK_CALL(vkGetPhysicalDeviceFormatProperties(device->vk_physical_device, format->vk_format, &properties));
+            image_features = properties.linearTilingFeatures | properties.optimalTilingFeatures;
+
+            if (properties.bufferFeatures)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_BUFFER;
+            if (properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER;
+            if (data->Format == DXGI_FORMAT_R16_UINT || data->Format == DXGI_FORMAT_R32_UINT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER;
+            if (image_features)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_TEXTURE1D | D3D12_FORMAT_SUPPORT1_TEXTURE2D
+                        | D3D12_FORMAT_SUPPORT1_TEXTURE3D | D3D12_FORMAT_SUPPORT1_TEXTURECUBE;
+            if (image_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
+            {
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD
+                        | D3D12_FORMAT_SUPPORT1_SHADER_GATHER;
+                if (image_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
+                {
+                    data->Support1 |= D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE
+                            | D3D12_FORMAT_SUPPORT1_MIP;
+                }
+                if (format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT)
+                    data->Support1 |= D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON
+                            | D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON;
+            }
+            if (image_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_RENDER_TARGET | D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET;
+            if (image_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_BLENDABLE;
+            if (image_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL;
+            if (image_features & VK_FORMAT_FEATURE_BLIT_SRC_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE;
+            if (image_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
+                data->Support1 |= D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW;
+
+            if (image_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)
+                data->Support2 |= D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD
+                        | D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS
+                        | D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE
+                        | D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE
+                        | D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX
+                        | D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX;
+
+            vkd3d_restrict_format_support_for_feature_level(data);
+
+            TRACE("Format %#x, support1 %#x, support2 %#x.\n", data->Format, data->Support1, data->Support2);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS:
+        {
+            D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            return d3d12_device_check_multisample_quality_levels(device, data);
+        }
+
+        case D3D12_FEATURE_FORMAT_INFO:
+        {
+            D3D12_FEATURE_DATA_FORMAT_INFO *data = feature_data;
+            const struct vkd3d_format *format;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            if (data->Format == DXGI_FORMAT_UNKNOWN)
+            {
+                data->PlaneCount = 1;
+                return S_OK;
+            }
+
+            if (!(format = vkd3d_get_format(device, data->Format, false)))
+                format = vkd3d_get_format(device, data->Format, true);
+            if (!format)
+            {
+                FIXME("Unhandled format %#x.\n", data->Format);
+                return E_INVALIDARG;
+            }
+
+            data->PlaneCount = format->plane_count;
+
+            TRACE("Format %#x, plane count %"PRIu8".\n", data->Format, data->PlaneCount);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT:
+        {
+            const D3D12_FEATURE_DATA_D3D12_OPTIONS *options = &device->feature_options;
+            D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            data->MaxGPUVirtualAddressBitsPerResource = options->MaxGPUVirtualAddressBitsPerResource;
+            data->MaxGPUVirtualAddressBitsPerProcess = options->MaxGPUVirtualAddressBitsPerResource;
+
+            TRACE("Max GPU virtual address bits per resource %u, Max GPU virtual address bits per process %u.\n",
+                    data->MaxGPUVirtualAddressBitsPerResource, data->MaxGPUVirtualAddressBitsPerProcess);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_SHADER_MODEL:
+        {
+            D3D12_FEATURE_DATA_SHADER_MODEL *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            TRACE("Request shader model %#x.\n", data->HighestShaderModel);
+
+            data->HighestShaderModel = D3D_SHADER_MODEL_5_1;
+
+            TRACE("Shader model %#x.\n", data->HighestShaderModel);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_D3D12_OPTIONS1:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS1 *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options1;
+
+            TRACE("Wave ops %#x.\n", data->WaveOps);
+            TRACE("Min wave lane count %#x.\n", data->WaveLaneCountMin);
+            TRACE("Max wave lane count %#x.\n", data->WaveLaneCountMax);
+            TRACE("Total lane count %#x.\n", data->TotalLaneCount);
+            TRACE("Expanded compute resource states %#x.\n", data->ExpandedComputeResourceStates);
+            TRACE("Int64 shader ops %#x.\n", data->Int64ShaderOps);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_ROOT_SIGNATURE:
+        {
+            D3D12_FEATURE_DATA_ROOT_SIGNATURE *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            TRACE("Root signature requested %#x.\n", data->HighestVersion);
+            data->HighestVersion = min(data->HighestVersion, D3D_ROOT_SIGNATURE_VERSION_1_1);
+            if (device->vkd3d_instance->api_version < VKD3D_API_VERSION_1_2)
+                data->HighestVersion = min(data->HighestVersion, D3D_ROOT_SIGNATURE_VERSION_1_0);
+
+            TRACE("Root signature version %#x.\n", data->HighestVersion);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_ARCHITECTURE1:
+        {
+            D3D12_FEATURE_DATA_ARCHITECTURE1 *data = feature_data;
+            bool coherent;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            if (data->NodeIndex)
+            {
+                FIXME("Multi-adapter not supported.\n");
+                return E_INVALIDARG;
+            }
+
+            WARN("Assuming device does not support tile based rendering.\n");
+            data->TileBasedRenderer = FALSE;
+
+            data->UMA = d3d12_device_is_uma(device, &coherent);
+            data->CacheCoherentUMA = data->UMA && coherent;
+
+            WARN("Assuming device does not have an isolated memory management unit.\n");
+            data->IsolatedMMU = FALSE;
+
+            TRACE("Tile based renderer %#x, UMA %#x, cache coherent UMA %#x, isolated MMU %#x.\n",
+                    data->TileBasedRenderer, data->UMA, data->CacheCoherentUMA, data->IsolatedMMU);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_D3D12_OPTIONS2:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS2 *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options2;
+
+            TRACE("Depth bounds test %#x.\n", data->DepthBoundsTestSupported);
+            TRACE("Programmable sample positions tier %#x.\n", data->ProgrammableSamplePositionsTier);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_SHADER_CACHE:
+        {
+            D3D12_FEATURE_DATA_SHADER_CACHE *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            /* FIXME: The d3d12 documentation states that
+             * D3D12_SHADER_CACHE_SUPPORT_SINGLE_PSO is always supported, but
+             * the CachedPSO field of D3D12_GRAPHICS_PIPELINE_STATE_DESC is
+             * ignored and GetCachedBlob() is a stub. */
+            data->SupportFlags = D3D12_SHADER_CACHE_SUPPORT_NONE;
+
+            TRACE("Shader cache support %#x.\n", data->SupportFlags);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_COMMAND_QUEUE_PRIORITY:
+        {
+            D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            switch (data->CommandListType)
+            {
+                case D3D12_COMMAND_LIST_TYPE_DIRECT:
+                case D3D12_COMMAND_LIST_TYPE_COMPUTE:
+                case D3D12_COMMAND_LIST_TYPE_COPY:
+                    data->PriorityForTypeIsSupported = FALSE;
+                    TRACE("Command list type %#x, priority %u, supported %#x.\n",
+                            data->CommandListType, data->Priority, data->PriorityForTypeIsSupported);
+                    return S_OK;
+
+                default:
+                    FIXME("Unhandled command list type %#x.\n", data->CommandListType);
+                    return E_INVALIDARG;
+            }
+        }
+
+        case D3D12_FEATURE_D3D12_OPTIONS3:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS3 *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options3;
+
+            TRACE("Copy queue timestamp queries %#x.\n", data->CopyQueueTimestampQueriesSupported);
+            TRACE("Casting fully typed format %#x.\n", data->CastingFullyTypedFormatSupported);
+            TRACE("Write buffer immediate %#x.\n", data->WriteBufferImmediateSupportFlags);
+            TRACE("View instancing tier %#x.\n", data->ViewInstancingTier);
+            TRACE("Barycentrics %#x.\n", data->BarycentricsSupported);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_EXISTING_HEAPS:
+        {
+            D3D12_FEATURE_DATA_EXISTING_HEAPS *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            data->Supported = FALSE;
+
+            TRACE("Existing heaps %#x.\n", data->Supported);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_D3D12_OPTIONS4:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS4 *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options4;
+
+            TRACE("64 KiB aligned MSAA textures %#x.\n", data->MSAA64KBAlignedTextureSupported);
+            TRACE("Shared resource compatibility tier %#x.\n", data->SharedResourceCompatibilityTier);
+            TRACE("Native 16-bit shader ops %#x.\n", data->Native16BitShaderOpsSupported);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_SERIALIZATION:
+        {
+            D3D12_FEATURE_DATA_SERIALIZATION *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            if (data->NodeIndex)
+            {
+                FIXME("Multi-adapter not supported.\n");
+                return E_INVALIDARG;
+            }
+
+            data->HeapSerializationTier = D3D12_HEAP_SERIALIZATION_TIER_0;
+
+            TRACE("Heap serialisation tier %#x.\n", data->HeapSerializationTier);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_CROSS_NODE:
+        {
+            D3D12_FEATURE_DATA_CROSS_NODE *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            data->SharingTier = device->feature_options.CrossNodeSharingTier;
+            data->AtomicShaderInstructions = FALSE;
+
+            TRACE("Cross node sharing tier %#x.\n", data->SharingTier);
+            TRACE("Cross node shader atomics %#x.\n", data->AtomicShaderInstructions);
+            return S_OK;
+        }
+
+        case D3D12_FEATURE_D3D12_OPTIONS5:
+        {
+            D3D12_FEATURE_DATA_D3D12_OPTIONS5 *data = feature_data;
+
+            if (feature_data_size != sizeof(*data))
+            {
+                WARN("Invalid size %u.\n", feature_data_size);
+                return E_INVALIDARG;
+            }
+
+            *data = device->feature_options5;
+
+            TRACE("SRV tiled resource tier 3 only %#x.\n", data->SRVOnlyTiledResourceTier3);
+            TRACE("Render pass tier %#x.\n", data->RenderPassesTier);
+            TRACE("Ray tracing tier %#x.\n", data->RaytracingTier);
+            return S_OK;
+        }
+
+        default:
+            FIXME("Unhandled feature %#x.\n", feature);
+            return E_NOTIMPL;
+    }
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateDescriptorHeap(ID3D12Device *iface,
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc, REFIID riid, void **descriptor_heap)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_descriptor_heap *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, riid %s, descriptor_heap %p.\n",
+            iface, desc, debugstr_guid(riid), descriptor_heap);
+
+    if (FAILED(hr = d3d12_descriptor_heap_create(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12DescriptorHeap_iface,
+            &IID_ID3D12DescriptorHeap, riid, descriptor_heap);
+}
+
+static UINT STDMETHODCALLTYPE d3d12_device_GetDescriptorHandleIncrementSize(ID3D12Device *iface,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
+{
+    TRACE("iface %p, descriptor_heap_type %#x.\n", iface, descriptor_heap_type);
+
+    switch (descriptor_heap_type)
+    {
+        case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV:
+        case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER:
+            return sizeof(struct d3d12_desc);
+
+        case D3D12_DESCRIPTOR_HEAP_TYPE_RTV:
+            return sizeof(struct d3d12_rtv_desc);
+
+        case D3D12_DESCRIPTOR_HEAP_TYPE_DSV:
+            return sizeof(struct d3d12_dsv_desc);
+
+        default:
+            FIXME("Unhandled type %#x.\n", descriptor_heap_type);
+            return 0;
+    }
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateRootSignature(ID3D12Device *iface,
+        UINT node_mask, const void *bytecode, SIZE_T bytecode_length,
+        REFIID riid, void **root_signature)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_root_signature *object;
+    HRESULT hr;
+
+    TRACE("iface %p, node_mask 0x%08x, bytecode %p, bytecode_length %lu, riid %s, root_signature %p.\n",
+            iface, node_mask, bytecode, bytecode_length, debugstr_guid(riid), root_signature);
+
+    debug_ignored_node_mask(node_mask);
+
+    if (FAILED(hr = d3d12_root_signature_create(device, bytecode, bytecode_length, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12RootSignature_iface,
+            &IID_ID3D12RootSignature, riid, root_signature);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateConstantBufferView(ID3D12Device *iface,
+        const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_desc tmp = {0};
+
+    TRACE("iface %p, desc %p, descriptor %#lx.\n", iface, desc, descriptor.ptr);
+
+    d3d12_desc_create_cbv(&tmp, device, desc);
+    d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateShaderResourceView(ID3D12Device *iface,
+        ID3D12Resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_desc tmp = {0};
+
+    TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
+            iface, resource, desc, descriptor.ptr);
+
+    d3d12_desc_create_srv(&tmp, device, unsafe_impl_from_ID3D12Resource(resource), desc);
+    d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateUnorderedAccessView(ID3D12Device *iface,
+        ID3D12Resource *resource, ID3D12Resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_desc tmp = {0};
+
+    TRACE("iface %p, resource %p, counter_resource %p, desc %p, descriptor %#lx.\n",
+            iface, resource, counter_resource, desc, descriptor.ptr);
+
+    d3d12_desc_create_uav(&tmp, device, unsafe_impl_from_ID3D12Resource(resource),
+            unsafe_impl_from_ID3D12Resource(counter_resource), desc);
+    d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateRenderTargetView(ID3D12Device *iface,
+        ID3D12Resource *resource, const D3D12_RENDER_TARGET_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
+            iface, resource, desc, descriptor.ptr);
+
+    d3d12_rtv_desc_create_rtv(d3d12_rtv_desc_from_cpu_handle(descriptor),
+            impl_from_ID3D12Device(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateDepthStencilView(ID3D12Device *iface,
+        ID3D12Resource *resource, const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
+        D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
+            iface, resource, desc, descriptor.ptr);
+
+    d3d12_dsv_desc_create_dsv(d3d12_dsv_desc_from_cpu_handle(descriptor),
+            impl_from_ID3D12Device(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CreateSampler(ID3D12Device *iface,
+        const D3D12_SAMPLER_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_desc tmp = {0};
+
+    TRACE("iface %p, desc %p, descriptor %#lx.\n", iface, desc, descriptor.ptr);
+
+    d3d12_desc_create_sampler(&tmp, device, desc);
+    d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface,
+        UINT dst_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
+        const UINT *dst_descriptor_range_sizes,
+        UINT src_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
+        const UINT *src_descriptor_range_sizes,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    unsigned int dst_range_idx, dst_idx, src_range_idx, src_idx;
+    unsigned int dst_range_size, src_range_size;
+    const struct d3d12_desc *src;
+    struct d3d12_desc *dst;
+
+    TRACE("iface %p, dst_descriptor_range_count %u, dst_descriptor_range_offsets %p, "
+            "dst_descriptor_range_sizes %p, src_descriptor_range_count %u, "
+            "src_descriptor_range_offsets %p, src_descriptor_range_sizes %p, "
+            "descriptor_heap_type %#x.\n",
+            iface, dst_descriptor_range_count, dst_descriptor_range_offsets,
+            dst_descriptor_range_sizes, src_descriptor_range_count, src_descriptor_range_offsets,
+            src_descriptor_range_sizes, descriptor_heap_type);
+
+    if (descriptor_heap_type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
+            && descriptor_heap_type != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
+    {
+        FIXME("Unhandled descriptor heap type %#x.\n", descriptor_heap_type);
+        return;
+    }
+
+    dst_range_idx = dst_idx = 0;
+    src_range_idx = src_idx = 0;
+    while (dst_range_idx < dst_descriptor_range_count && src_range_idx < src_descriptor_range_count)
+    {
+        dst_range_size = dst_descriptor_range_sizes ? dst_descriptor_range_sizes[dst_range_idx] : 1;
+        src_range_size = src_descriptor_range_sizes ? src_descriptor_range_sizes[src_range_idx] : 1;
+
+        dst = d3d12_desc_from_cpu_handle(dst_descriptor_range_offsets[dst_range_idx]);
+        src = d3d12_desc_from_cpu_handle(src_descriptor_range_offsets[src_range_idx]);
+
+        while (dst_idx < dst_range_size && src_idx < src_range_size)
+            d3d12_desc_copy(&dst[dst_idx++], &src[src_idx++], device);
+
+        if (dst_idx >= dst_range_size)
+        {
+            ++dst_range_idx;
+            dst_idx = 0;
+        }
+        if (src_idx >= src_range_size)
+        {
+            ++src_range_idx;
+            src_idx = 0;
+        }
+    }
+}
+
+static void STDMETHODCALLTYPE d3d12_device_CopyDescriptorsSimple(ID3D12Device *iface,
+        UINT descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
+        const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
+{
+    TRACE("iface %p, descriptor_count %u, dst_descriptor_range_offset %#lx, "
+            "src_descriptor_range_offset %#lx, descriptor_heap_type %#x.\n",
+            iface, descriptor_count, dst_descriptor_range_offset.ptr, src_descriptor_range_offset.ptr,
+            descriptor_heap_type);
+
+    d3d12_device_CopyDescriptors(iface, 1, &dst_descriptor_range_offset, &descriptor_count,
+            1, &src_descriptor_range_offset, &descriptor_count, descriptor_heap_type);
+}
+
+static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResourceAllocationInfo(
+        ID3D12Device *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
+        UINT count, const D3D12_RESOURCE_DESC *resource_descs)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    const D3D12_RESOURCE_DESC *desc;
+    uint64_t requested_alignment;
+
+    TRACE("iface %p, info %p, visible_mask 0x%08x, count %u, resource_descs %p.\n",
+            iface, info, visible_mask, count, resource_descs);
+
+    debug_ignored_node_mask(visible_mask);
+
+    info->SizeInBytes = 0;
+    info->Alignment = 0;
+
+    if (count != 1)
+    {
+        FIXME("Multiple resource descriptions not supported.\n");
+        return info;
+    }
+
+    desc = &resource_descs[0];
+
+    if (FAILED(d3d12_resource_validate_desc(desc, device)))
+    {
+        WARN("Invalid resource desc.\n");
+        goto invalid;
+    }
+
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+    {
+        info->SizeInBytes = desc->Width;
+        info->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    }
+    else
+    {
+        if (FAILED(vkd3d_get_image_allocation_info(device, desc, info)))
+        {
+            WARN("Failed to get allocation info for texture.\n");
+            goto invalid;
+        }
+
+        requested_alignment = desc->Alignment
+                ? desc->Alignment : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+        info->Alignment = max(info->Alignment, requested_alignment);
+    }
+
+    info->SizeInBytes = align(info->SizeInBytes, info->Alignment);
+
+    TRACE("Size %#"PRIx64", alignment %#"PRIx64".\n", info->SizeInBytes, info->Alignment);
+
+    return info;
+
+invalid:
+    info->SizeInBytes = ~(uint64_t)0;
+
+    /* FIXME: Should we support D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT for small MSSA resources? */
+    if (desc->SampleDesc.Count != 1)
+        info->Alignment = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT;
+    else
+        info->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+
+    TRACE("Alignment %#"PRIx64".\n", info->Alignment);
+
+    return info;
+}
+
+static D3D12_HEAP_PROPERTIES * STDMETHODCALLTYPE d3d12_device_GetCustomHeapProperties(ID3D12Device *iface,
+        D3D12_HEAP_PROPERTIES *heap_properties, UINT node_mask, D3D12_HEAP_TYPE heap_type)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    bool coherent;
+
+    TRACE("iface %p, heap_properties %p, node_mask 0x%08x, heap_type %#x.\n",
+            iface, heap_properties, node_mask, heap_type);
+
+    debug_ignored_node_mask(node_mask);
+
+    heap_properties->Type = D3D12_HEAP_TYPE_CUSTOM;
+
+    switch (heap_type)
+    {
+        case D3D12_HEAP_TYPE_DEFAULT:
+            heap_properties->CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
+            heap_properties->MemoryPoolPreference = d3d12_device_is_uma(device, NULL)
+                    ?  D3D12_MEMORY_POOL_L0 : D3D12_MEMORY_POOL_L1;
+            break;
+
+        case D3D12_HEAP_TYPE_UPLOAD:
+            heap_properties->CPUPageProperty = d3d12_device_is_uma(device, &coherent) && coherent
+                    ? D3D12_CPU_PAGE_PROPERTY_WRITE_BACK : D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
+            heap_properties->MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
+            break;
+
+        case D3D12_HEAP_TYPE_READBACK:
+            heap_properties->CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
+            heap_properties->MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
+            break;
+
+        default:
+            FIXME("Unhandled heap type %#x.\n", heap_type);
+            break;
+    };
+
+    heap_properties->CreationNodeMask = 1;
+    heap_properties->VisibleNodeMask = 1;
+
+    return heap_properties;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource(ID3D12Device *iface,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    TRACE("iface %p, heap_properties %p, heap_flags %#x,  desc %p, initial_state %#x, "
+            "optimized_clear_value %p, iid %s, resource %p.\n",
+            iface, heap_properties, heap_flags, desc, initial_state,
+            optimized_clear_value, debugstr_guid(iid), resource);
+
+    if (FAILED(hr = d3d12_committed_resource_create(device, heap_properties, heap_flags,
+            desc, initial_state, optimized_clear_value, &object)))
+    {
+        *resource = NULL;
+        return hr;
+    }
+
+    return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap(ID3D12Device *iface,
+        const D3D12_HEAP_DESC *desc, REFIID iid, void **heap)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_heap *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, iid %s, heap %p.\n",
+            iface, desc, debugstr_guid(iid), heap);
+
+    if (FAILED(hr = d3d12_heap_create(device, desc, NULL, &object)))
+    {
+        *heap = NULL;
+        return hr;
+    }
+
+    return return_interface(&object->ID3D12Heap_iface, &IID_ID3D12Heap, iid, heap);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource(ID3D12Device *iface,
+        ID3D12Heap *heap, UINT64 heap_offset,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_heap *heap_object;
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    TRACE("iface %p, heap %p, heap_offset %#"PRIx64", desc %p, initial_state %#x, "
+            "optimized_clear_value %p, iid %s, resource %p.\n",
+            iface, heap, heap_offset, desc, initial_state,
+            optimized_clear_value, debugstr_guid(iid), resource);
+
+    heap_object = unsafe_impl_from_ID3D12Heap(heap);
+
+    if (FAILED(hr = d3d12_placed_resource_create(device, heap_object, heap_offset,
+            desc, initial_state, optimized_clear_value, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource(ID3D12Device *iface,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, initial_state %#x, optimized_clear_value %p, iid %s, resource %p.\n",
+            iface, desc, initial_state, optimized_clear_value, debugstr_guid(iid), resource);
+
+    if (FAILED(hr = d3d12_reserved_resource_create(device,
+            desc, initial_state, optimized_clear_value, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateSharedHandle(ID3D12Device *iface,
+        ID3D12DeviceChild *object, const SECURITY_ATTRIBUTES *attributes, DWORD access,
+        const WCHAR *name, HANDLE *handle)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    FIXME("iface %p, object %p, attributes %p, access %#x, name %s, handle %p stub!\n",
+            iface, object, attributes, access, debugstr_w(name, device->wchar_size), handle);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandle(ID3D12Device *iface,
+        HANDLE handle, REFIID riid, void **object)
+{
+    FIXME("iface %p, handle %p, riid %s, object %p stub!\n",
+            iface, handle, debugstr_guid(riid), object);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandleByName(ID3D12Device *iface,
+        const WCHAR *name, DWORD access, HANDLE *handle)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    FIXME("iface %p, name %s, access %#x, handle %p stub!\n",
+            iface, debugstr_w(name, device->wchar_size), access, handle);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_MakeResident(ID3D12Device *iface,
+        UINT object_count, ID3D12Pageable * const *objects)
+{
+    FIXME_ONCE("iface %p, object_count %u, objects %p stub!\n",
+            iface, object_count, objects);
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_Evict(ID3D12Device *iface,
+        UINT object_count, ID3D12Pageable * const *objects)
+{
+    FIXME_ONCE("iface %p, object_count %u, objects %p stub!\n",
+            iface, object_count, objects);
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateFence(ID3D12Device *iface,
+        UINT64 initial_value, D3D12_FENCE_FLAGS flags, REFIID riid, void **fence)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_fence *object;
+    HRESULT hr;
+
+    TRACE("iface %p, intial_value %#"PRIx64", flags %#x, riid %s, fence %p.\n",
+            iface, initial_value, flags, debugstr_guid(riid), fence);
+
+    if (FAILED(hr = d3d12_fence_create(device, initial_value, flags, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12Fence_iface, &IID_ID3D12Fence, riid, fence);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_GetDeviceRemovedReason(ID3D12Device *iface)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->removed_reason;
+}
+
+static void STDMETHODCALLTYPE d3d12_device_GetCopyableFootprints(ID3D12Device *iface,
+        const D3D12_RESOURCE_DESC *desc, UINT first_sub_resource, UINT sub_resource_count,
+        UINT64 base_offset, D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
+        UINT *row_counts, UINT64 *row_sizes, UINT64 *total_bytes)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    static const struct vkd3d_format vkd3d_format_unknown
+            = {DXGI_FORMAT_UNKNOWN, VK_FORMAT_UNDEFINED, 1, 1, 1, 1, 0};
+
+    unsigned int i, sub_resource_idx, miplevel_idx, row_count, row_size, row_pitch;
+    unsigned int width, height, depth, array_size;
+    const struct vkd3d_format *format;
+    uint64_t offset, size, total;
+
+    TRACE("iface %p, desc %p, first_sub_resource %u, sub_resource_count %u, base_offset %#"PRIx64", "
+            "layouts %p, row_counts %p, row_sizes %p, total_bytes %p.\n",
+            iface, desc, first_sub_resource, sub_resource_count, base_offset,
+            layouts, row_counts, row_sizes, total_bytes);
+
+    if (layouts)
+        memset(layouts, 0xff, sizeof(*layouts) * sub_resource_count);
+    if (row_counts)
+        memset(row_counts, 0xff, sizeof(*row_counts) * sub_resource_count);
+    if (row_sizes)
+        memset(row_sizes, 0xff, sizeof(*row_sizes) * sub_resource_count);
+    if (total_bytes)
+        *total_bytes = ~(uint64_t)0;
+
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+    {
+        format = &vkd3d_format_unknown;
+    }
+    else if (!(format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0)))
+    {
+        WARN("Invalid format %#x.\n", desc->Format);
+        return;
+    }
+
+    if (FAILED(d3d12_resource_validate_desc(desc, device)))
+    {
+        WARN("Invalid resource desc.\n");
+        return;
+    }
+
+    array_size = d3d12_resource_desc_get_layer_count(desc);
+
+    if (first_sub_resource >= desc->MipLevels * array_size
+            || sub_resource_count > desc->MipLevels * array_size - first_sub_resource)
+    {
+        WARN("Invalid sub-resource range %u-%u for resource.\n", first_sub_resource, sub_resource_count);
+        return;
+    }
+
+    offset = 0;
+    total = 0;
+    for (i = 0; i < sub_resource_count; ++i)
+    {
+        sub_resource_idx = first_sub_resource + i;
+        miplevel_idx = sub_resource_idx % desc->MipLevels;
+        width = align(d3d12_resource_desc_get_width(desc, miplevel_idx), format->block_width);
+        height = align(d3d12_resource_desc_get_height(desc, miplevel_idx), format->block_height);
+        depth = d3d12_resource_desc_get_depth(desc, miplevel_idx);
+        row_count = height / format->block_height;
+        row_size = (width / format->block_width) * format->byte_count * format->block_byte_count;
+        row_pitch = align(row_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+
+        if (layouts)
+        {
+            layouts[i].Offset = base_offset + offset;
+            layouts[i].Footprint.Format = desc->Format;
+            layouts[i].Footprint.Width = width;
+            layouts[i].Footprint.Height = height;
+            layouts[i].Footprint.Depth = depth;
+            layouts[i].Footprint.RowPitch = row_pitch;
+        }
+        if (row_counts)
+            row_counts[i] = row_count;
+        if (row_sizes)
+            row_sizes[i] = row_size;
+
+        size = max(0, row_count - 1) * row_pitch + row_size;
+        size = max(0, depth - 1) * align(size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) + size;
+
+        total = offset + size;
+        offset = align(total, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
+    }
+    if (total_bytes)
+        *total_bytes = total;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateQueryHeap(ID3D12Device *iface,
+        const D3D12_QUERY_HEAP_DESC *desc, REFIID iid, void **heap)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_query_heap *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, iid %s, heap %p.\n",
+            iface, desc, debugstr_guid(iid), heap);
+
+    if (FAILED(hr = d3d12_query_heap_create(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12QueryHeap_iface, &IID_ID3D12QueryHeap, iid, heap);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetStablePowerState(ID3D12Device *iface, BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandSignature(ID3D12Device *iface,
+        const D3D12_COMMAND_SIGNATURE_DESC *desc, ID3D12RootSignature *root_signature,
+        REFIID iid, void **command_signature)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+    struct d3d12_command_signature *object;
+    HRESULT hr;
+
+    TRACE("iface %p, desc %p, root_signature %p, iid %s, command_signature %p.\n",
+            iface, desc, root_signature, debugstr_guid(iid), command_signature);
+
+    if (FAILED(hr = d3d12_command_signature_create(device, desc, &object)))
+        return hr;
+
+    return return_interface(&object->ID3D12CommandSignature_iface,
+            &IID_ID3D12CommandSignature, iid, command_signature);
+}
+
+static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device *iface,
+        ID3D12Resource *resource, UINT *total_tile_count,
+        D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling,
+        D3D12_SUBRESOURCE_TILING *sub_resource_tilings)
+{
+    FIXME("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, "
+            "standard_title_shape %p, sub_resource_tiling_count %p, "
+            "first_sub_resource_tiling %u, sub_resource_tilings %p stub!\n",
+            iface, resource, total_tile_count, packed_mip_info, standard_tile_shape,
+            sub_resource_tiling_count, first_sub_resource_tiling,
+            sub_resource_tilings);
+}
+
+static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device *iface, LUID *luid)
+{
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, luid %p.\n", iface, luid);
+
+    *luid = device->adapter_luid;
+
+    return luid;
+}
+
+static const struct ID3D12DeviceVtbl d3d12_device_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_device_QueryInterface,
+    d3d12_device_AddRef,
+    d3d12_device_Release,
+    /* ID3D12Object methods */
+    d3d12_device_GetPrivateData,
+    d3d12_device_SetPrivateData,
+    d3d12_device_SetPrivateDataInterface,
+    d3d12_device_SetName,
+    /* ID3D12Device methods */
+    d3d12_device_GetNodeCount,
+    d3d12_device_CreateCommandQueue,
+    d3d12_device_CreateCommandAllocator,
+    d3d12_device_CreateGraphicsPipelineState,
+    d3d12_device_CreateComputePipelineState,
+    d3d12_device_CreateCommandList,
+    d3d12_device_CheckFeatureSupport,
+    d3d12_device_CreateDescriptorHeap,
+    d3d12_device_GetDescriptorHandleIncrementSize,
+    d3d12_device_CreateRootSignature,
+    d3d12_device_CreateConstantBufferView,
+    d3d12_device_CreateShaderResourceView,
+    d3d12_device_CreateUnorderedAccessView,
+    d3d12_device_CreateRenderTargetView,
+    d3d12_device_CreateDepthStencilView,
+    d3d12_device_CreateSampler,
+    d3d12_device_CopyDescriptors,
+    d3d12_device_CopyDescriptorsSimple,
+    d3d12_device_GetResourceAllocationInfo,
+    d3d12_device_GetCustomHeapProperties,
+    d3d12_device_CreateCommittedResource,
+    d3d12_device_CreateHeap,
+    d3d12_device_CreatePlacedResource,
+    d3d12_device_CreateReservedResource,
+    d3d12_device_CreateSharedHandle,
+    d3d12_device_OpenSharedHandle,
+    d3d12_device_OpenSharedHandleByName,
+    d3d12_device_MakeResident,
+    d3d12_device_Evict,
+    d3d12_device_CreateFence,
+    d3d12_device_GetDeviceRemovedReason,
+    d3d12_device_GetCopyableFootprints,
+    d3d12_device_CreateQueryHeap,
+    d3d12_device_SetStablePowerState,
+    d3d12_device_CreateCommandSignature,
+    d3d12_device_GetResourceTiling,
+    d3d12_device_GetAdapterLuid,
+};
+
+struct d3d12_device *unsafe_impl_from_ID3D12Device(ID3D12Device *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_device_vtbl);
+    return impl_from_ID3D12Device(iface);
+}
+
+static HRESULT d3d12_device_init(struct d3d12_device *device,
+        struct vkd3d_instance *instance, const struct vkd3d_device_create_info *create_info)
+{
+    const struct vkd3d_vk_device_procs *vk_procs;
+    HRESULT hr;
+    size_t i;
+
+    device->ID3D12Device_iface.lpVtbl = &d3d12_device_vtbl;
+    device->refcount = 1;
+
+    vkd3d_instance_incref(device->vkd3d_instance = instance);
+    device->vk_info = instance->vk_info;
+    device->signal_event = instance->signal_event;
+    device->wchar_size = instance->wchar_size;
+
+    device->adapter_luid = create_info->adapter_luid;
+    device->removed_reason = S_OK;
+
+    device->vk_device = VK_NULL_HANDLE;
+
+    if (FAILED(hr = vkd3d_create_vk_device(device, create_info)))
+        goto out_free_instance;
+
+    if (FAILED(hr = d3d12_device_init_pipeline_cache(device)))
+        goto out_free_vk_resources;
+
+    if (FAILED(hr = vkd3d_private_store_init(&device->private_store)))
+        goto out_free_pipeline_cache;
+
+    if (FAILED(hr = vkd3d_fence_worker_start(&device->fence_worker, device)))
+        goto out_free_private_store;
+
+    if (FAILED(hr = vkd3d_init_format_info(device)))
+        goto out_stop_fence_worker;
+
+    if (FAILED(hr = vkd3d_init_null_resources(&device->null_resources, device)))
+        goto out_cleanup_format_info;
+
+    if (FAILED(hr = vkd3d_uav_clear_state_init(&device->uav_clear_state, device)))
+        goto out_destroy_null_resources;
+
+    vkd3d_render_pass_cache_init(&device->render_pass_cache);
+    vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator);
+
+    for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i)
+        pthread_mutex_init(&device->desc_mutex[i], NULL);
+
+    if ((device->parent = create_info->parent))
+        IUnknown_AddRef(device->parent);
+
+    return S_OK;
+
+out_destroy_null_resources:
+    vkd3d_destroy_null_resources(&device->null_resources, device);
+out_cleanup_format_info:
+    vkd3d_cleanup_format_info(device);
+out_stop_fence_worker:
+    vkd3d_fence_worker_stop(&device->fence_worker, device);
+out_free_private_store:
+    vkd3d_private_store_destroy(&device->private_store);
+out_free_pipeline_cache:
+    d3d12_device_destroy_pipeline_cache(device);
+out_free_vk_resources:
+    vk_procs = &device->vk_procs;
+    VK_CALL(vkDestroyDevice(device->vk_device, NULL));
+out_free_instance:
+    vkd3d_instance_decref(device->vkd3d_instance);
+    return hr;
+}
+
+HRESULT d3d12_device_create(struct vkd3d_instance *instance,
+        const struct vkd3d_device_create_info *create_info, struct d3d12_device **device)
+{
+    struct d3d12_device *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_device_init(object, instance, create_info)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created device %p.\n", object);
+
+    *device = object;
+
+    return S_OK;
+}
+
+void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
+        const char *message, ...)
+{
+    va_list args;
+
+    va_start(args, message);
+    WARN("Device %p is lost (reason %#x, \"%s\").\n",
+            device, reason, vkd3d_dbg_vsprintf(message, args));
+    va_end(args);
+
+    device->removed_reason = reason;
+}
+
+HRESULT vkd3d_create_thread(struct vkd3d_instance *instance,
+        PFN_vkd3d_thread thread_main, void *data, union vkd3d_thread_handle *thread)
+{
+    HRESULT hr = S_OK;
+    int rc;
+
+    if (instance->create_thread)
+    {
+        if (!(thread->handle = instance->create_thread(thread_main, data)))
+        {
+            ERR("Failed to create thread.\n");
+            hr = E_FAIL;
+        }
+    }
+    else
+    {
+        if ((rc = pthread_create(&thread->pthread, NULL, thread_main, data)))
+        {
+            ERR("Failed to create thread, error %d.\n", rc);
+            hr = hresult_from_errno(rc);
+        }
+    }
+
+    return hr;
+}
+
+HRESULT vkd3d_join_thread(struct vkd3d_instance *instance, union vkd3d_thread_handle *thread)
+{
+    HRESULT hr = S_OK;
+    int rc;
+
+    if (instance->join_thread)
+    {
+        if (FAILED(hr = instance->join_thread(thread->handle)))
+            ERR("Failed to join thread, hr %#x.\n", hr);
+    }
+    else
+    {
+        if ((rc = pthread_join(thread->pthread, NULL)))
+        {
+            ERR("Failed to join thread, error %d.\n", rc);
+            hr = hresult_from_errno(rc);
+        }
+    }
+
+    return hr;
+}
+
+IUnknown *vkd3d_get_device_parent(ID3D12Device *device)
+{
+    struct d3d12_device *d3d12_device = impl_from_ID3D12Device(device);
+
+    return d3d12_device->parent;
+}
+
+VkDevice vkd3d_get_vk_device(ID3D12Device *device)
+{
+    struct d3d12_device *d3d12_device = impl_from_ID3D12Device(device);
+
+    return d3d12_device->vk_device;
+}
+
+VkPhysicalDevice vkd3d_get_vk_physical_device(ID3D12Device *device)
+{
+    struct d3d12_device *d3d12_device = impl_from_ID3D12Device(device);
+
+    return d3d12_device->vk_physical_device;
+}
+
+struct vkd3d_instance *vkd3d_instance_from_device(ID3D12Device *device)
+{
+    struct d3d12_device *d3d12_device = impl_from_ID3D12Device(device);
+
+    return d3d12_device->vkd3d_instance;
+}
diff --git a/dlls/vkd3d/libs/vkd3d/libvkd3d.pc.in b/dlls/vkd3d/libs/vkd3d/libvkd3d.pc.in
new file mode 100644
index 00000000000..e8b27295205
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/libvkd3d.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: vkd3d
+Description: The vkd3d 3D Graphics Library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}/vkd3d
+Libs: -L${libdir} -lvkd3d
diff --git a/dlls/vkd3d/libs/vkd3d/resource.c b/dlls/vkd3d/libs/vkd3d/resource.c
new file mode 100644
index 00000000000..a9d4d464fe7
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/resource.c
@@ -0,0 +1,4092 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2019 Conor McCarthy for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_private.h"
+
+#define VKD3D_NULL_BUFFER_SIZE 16
+#define VKD3D_NULL_VIEW_FORMAT DXGI_FORMAT_R8G8B8A8_UNORM
+
+static inline bool is_cpu_accessible_heap(const D3D12_HEAP_PROPERTIES *properties)
+{
+    if (properties->Type == D3D12_HEAP_TYPE_DEFAULT)
+        return false;
+    if (properties->Type == D3D12_HEAP_TYPE_CUSTOM)
+    {
+        return properties->CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE
+                || properties->CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
+    }
+    return true;
+}
+
+static HRESULT vkd3d_select_memory_type(struct d3d12_device *device, uint32_t memory_type_mask,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, unsigned int *type_index)
+{
+    const VkPhysicalDeviceMemoryProperties *memory_info = &device->memory_properties;
+    VkMemoryPropertyFlags flags[3];
+    unsigned int i, j, count = 0;
+
+    switch (heap_properties->Type)
+    {
+        case D3D12_HEAP_TYPE_DEFAULT:
+            flags[count++] = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+            break;
+
+        case D3D12_HEAP_TYPE_UPLOAD:
+            flags[count++] = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+            break;
+
+        case D3D12_HEAP_TYPE_READBACK:
+            flags[count++] = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+                    | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+            flags[count++] = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+            break;
+
+        case D3D12_HEAP_TYPE_CUSTOM:
+            if (heap_properties->MemoryPoolPreference == D3D12_MEMORY_POOL_UNKNOWN
+                    || (heap_properties->MemoryPoolPreference == D3D12_MEMORY_POOL_L1
+                    && (is_cpu_accessible_heap(heap_properties) || d3d12_device_is_uma(device, NULL))))
+            {
+                WARN("Invalid memory pool preference.\n");
+                return E_INVALIDARG;
+            }
+
+            switch (heap_properties->CPUPageProperty)
+            {
+                case D3D12_CPU_PAGE_PROPERTY_WRITE_BACK:
+                    flags[count++] = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+                            | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+                    /* Fall through. */
+                case D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE:
+                    flags[count++] = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+                    /* Fall through. */
+                case D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE:
+                    flags[count++] = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+                    break;
+                case D3D12_CPU_PAGE_PROPERTY_UNKNOWN:
+                default:
+                    WARN("Invalid CPU page property.\n");
+                    return E_INVALIDARG;
+            }
+            break;
+
+        default:
+            WARN("Invalid heap type %#x.\n", heap_properties->Type);
+            return E_INVALIDARG;
+    }
+
+    for (j = 0; j < count; ++j)
+    {
+        VkMemoryPropertyFlags preferred_flags = flags[j];
+
+        for (i = 0; i < memory_info->memoryTypeCount; ++i)
+        {
+            if (!(memory_type_mask & (1u << i)))
+                continue;
+            if ((memory_info->memoryTypes[i].propertyFlags & preferred_flags) == preferred_flags)
+            {
+                *type_index = i;
+                return S_OK;
+            }
+        }
+    }
+
+    return E_FAIL;
+}
+
+static HRESULT vkd3d_allocate_device_memory(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const VkMemoryRequirements *memory_requirements,
+        const VkMemoryDedicatedAllocateInfo *dedicated_allocate_info,
+        VkDeviceMemory *vk_memory, uint32_t *vk_memory_type)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkMemoryAllocateInfo allocate_info;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("Memory requirements: size %#"PRIx64", alignment %#"PRIx64".\n",
+            memory_requirements->size, memory_requirements->alignment);
+
+    allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    allocate_info.pNext = dedicated_allocate_info;
+    allocate_info.allocationSize = memory_requirements->size;
+    if (FAILED(hr = vkd3d_select_memory_type(device, memory_requirements->memoryTypeBits,
+            heap_properties, heap_flags, &allocate_info.memoryTypeIndex)))
+    {
+        if (hr != E_INVALIDARG)
+            FIXME("Failed to find suitable memory type (allowed types %#x).\n", memory_requirements->memoryTypeBits);
+        *vk_memory = VK_NULL_HANDLE;
+        return hr;
+    }
+
+    TRACE("Allocating memory type %u.\n", allocate_info.memoryTypeIndex);
+
+    if ((vr = VK_CALL(vkAllocateMemory(device->vk_device, &allocate_info, NULL, vk_memory))) < 0)
+    {
+        WARN("Failed to allocate device memory, vr %d.\n", vr);
+        *vk_memory = VK_NULL_HANDLE;
+        return hresult_from_vk_result(vr);
+    }
+
+    if (vk_memory_type)
+        *vk_memory_type = allocate_info.memoryTypeIndex;
+
+    return S_OK;
+}
+
+HRESULT vkd3d_allocate_buffer_memory(struct d3d12_device *device, VkBuffer vk_buffer,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        VkDeviceMemory *vk_memory, uint32_t *vk_memory_type, VkDeviceSize *vk_memory_size)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkMemoryDedicatedAllocateInfo *dedicated_allocation = NULL;
+    VkMemoryDedicatedRequirements dedicated_requirements;
+    VkMemoryDedicatedAllocateInfo dedicated_info;
+    VkMemoryRequirements2 memory_requirements2;
+    VkMemoryRequirements *memory_requirements;
+    VkBufferMemoryRequirementsInfo2 info;
+    VkResult vr;
+    HRESULT hr;
+
+    memory_requirements = &memory_requirements2.memoryRequirements;
+
+    if (device->vk_info.KHR_dedicated_allocation)
+    {
+        info.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2;
+        info.pNext = NULL;
+        info.buffer = vk_buffer;
+
+        dedicated_requirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+        dedicated_requirements.pNext = NULL;
+
+        memory_requirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+        memory_requirements2.pNext = &dedicated_requirements;
+
+        VK_CALL(vkGetBufferMemoryRequirements2KHR(device->vk_device, &info, &memory_requirements2));
+
+        if (dedicated_requirements.prefersDedicatedAllocation)
+        {
+            dedicated_allocation = &dedicated_info;
+
+            dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+            dedicated_info.pNext = NULL;
+            dedicated_info.image = VK_NULL_HANDLE;
+            dedicated_info.buffer = vk_buffer;
+        }
+    }
+    else
+    {
+        VK_CALL(vkGetBufferMemoryRequirements(device->vk_device, vk_buffer, memory_requirements));
+    }
+
+    if (FAILED(hr = vkd3d_allocate_device_memory(device, heap_properties, heap_flags,
+            memory_requirements, dedicated_allocation, vk_memory, vk_memory_type)))
+        return hr;
+
+    if ((vr = VK_CALL(vkBindBufferMemory(device->vk_device, vk_buffer, *vk_memory, 0))) < 0)
+    {
+        WARN("Failed to bind memory, vr %d.\n", vr);
+        VK_CALL(vkFreeMemory(device->vk_device, *vk_memory, NULL));
+        *vk_memory = VK_NULL_HANDLE;
+    }
+
+    if (vk_memory_size)
+        *vk_memory_size = memory_requirements->size;
+
+    return hresult_from_vk_result(vr);
+}
+
+static HRESULT vkd3d_allocate_image_memory(struct d3d12_device *device, VkImage vk_image,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        VkDeviceMemory *vk_memory, uint32_t *vk_memory_type, VkDeviceSize *vk_memory_size)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkMemoryDedicatedAllocateInfo *dedicated_allocation = NULL;
+    VkMemoryDedicatedRequirements dedicated_requirements;
+    VkMemoryDedicatedAllocateInfo dedicated_info;
+    VkMemoryRequirements2 memory_requirements2;
+    VkMemoryRequirements *memory_requirements;
+    VkImageMemoryRequirementsInfo2 info;
+    VkResult vr;
+    HRESULT hr;
+
+    memory_requirements = &memory_requirements2.memoryRequirements;
+
+    if (device->vk_info.KHR_dedicated_allocation)
+    {
+        info.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
+        info.pNext = NULL;
+        info.image = vk_image;
+
+        dedicated_requirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+        dedicated_requirements.pNext = NULL;
+
+        memory_requirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+        memory_requirements2.pNext = &dedicated_requirements;
+
+        VK_CALL(vkGetImageMemoryRequirements2KHR(device->vk_device, &info, &memory_requirements2));
+
+        if (dedicated_requirements.prefersDedicatedAllocation)
+        {
+            dedicated_allocation = &dedicated_info;
+
+            dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+            dedicated_info.pNext = NULL;
+            dedicated_info.image = vk_image;
+            dedicated_info.buffer = VK_NULL_HANDLE;
+        }
+    }
+    else
+    {
+        VK_CALL(vkGetImageMemoryRequirements(device->vk_device, vk_image, memory_requirements));
+    }
+
+    if (FAILED(hr = vkd3d_allocate_device_memory(device, heap_properties, heap_flags,
+            memory_requirements, dedicated_allocation, vk_memory, vk_memory_type)))
+        return hr;
+
+    if ((vr = VK_CALL(vkBindImageMemory(device->vk_device, vk_image, *vk_memory, 0))) < 0)
+    {
+        WARN("Failed to bind memory, vr %d.\n", vr);
+        VK_CALL(vkFreeMemory(device->vk_device, *vk_memory, NULL));
+        *vk_memory = VK_NULL_HANDLE;
+        return hresult_from_vk_result(vr);
+    }
+
+    if (vk_memory_size)
+        *vk_memory_size = memory_requirements->size;
+
+    return S_OK;
+}
+
+/* ID3D12Heap */
+static inline struct d3d12_heap *impl_from_ID3D12Heap(ID3D12Heap *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_heap, ID3D12Heap_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_QueryInterface(ID3D12Heap *iface,
+        REFIID iid, void **object)
+{
+    TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
+
+    if (IsEqualGUID(iid, &IID_ID3D12Heap)
+            || IsEqualGUID(iid, &IID_ID3D12Pageable)
+            || IsEqualGUID(iid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(iid, &IID_ID3D12Object)
+            || IsEqualGUID(iid, &IID_IUnknown))
+    {
+        ID3D12Heap_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_heap_AddRef(ID3D12Heap *iface)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+    ULONG refcount = InterlockedIncrement(&heap->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", heap, refcount);
+
+    assert(!heap->is_private);
+
+    return refcount;
+}
+
+static void d3d12_heap_destroy(struct d3d12_heap *heap)
+{
+    struct d3d12_device *device = heap->device;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    TRACE("Destroying heap %p.\n", heap);
+
+    vkd3d_private_store_destroy(&heap->private_store);
+
+    VK_CALL(vkFreeMemory(device->vk_device, heap->vk_memory, NULL));
+
+    pthread_mutex_destroy(&heap->mutex);
+
+    if (heap->is_private)
+        device = NULL;
+
+    vkd3d_free(heap);
+
+    if (device)
+        d3d12_device_release(device);
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+    ULONG refcount = InterlockedDecrement(&heap->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", heap, refcount);
+
+    if (!refcount)
+        d3d12_heap_destroy(heap);
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_GetPrivateData(ID3D12Heap *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_SetPrivateData(ID3D12Heap *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_SetPrivateDataInterface(ID3D12Heap *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&heap->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_SetName(ID3D12Heap *iface, const WCHAR *name)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, heap->device->wchar_size));
+
+    return vkd3d_set_vk_object_name(heap->device, (uint64_t)heap->vk_memory,
+            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, name);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_heap_GetDevice(ID3D12Heap *iface, REFIID iid, void **device)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(heap->device, iid, device);
+}
+
+static D3D12_HEAP_DESC * STDMETHODCALLTYPE d3d12_heap_GetDesc(ID3D12Heap *iface,
+        D3D12_HEAP_DESC *desc)
+{
+    struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
+
+    TRACE("iface %p, desc %p.\n", iface, desc);
+
+    *desc = heap->desc;
+    return desc;
+}
+
+static const struct ID3D12HeapVtbl d3d12_heap_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_heap_QueryInterface,
+    d3d12_heap_AddRef,
+    d3d12_heap_Release,
+    /* ID3D12Object methods */
+    d3d12_heap_GetPrivateData,
+    d3d12_heap_SetPrivateData,
+    d3d12_heap_SetPrivateDataInterface,
+    d3d12_heap_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_heap_GetDevice,
+    /* ID3D12Heap methods */
+    d3d12_heap_GetDesc,
+};
+
+struct d3d12_heap *unsafe_impl_from_ID3D12Heap(ID3D12Heap *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_heap_vtbl);
+    return impl_from_ID3D12Heap(iface);
+}
+
+static HRESULT d3d12_heap_map(struct d3d12_heap *heap, uint64_t offset,
+        struct d3d12_resource *resource, void **data)
+{
+    struct d3d12_device *device = heap->device;
+    HRESULT hr = S_OK;
+    VkResult vr;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&heap->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        if (data)
+            *data = NULL;
+        return hresult_from_errno(rc);
+    }
+
+    assert(!resource->map_count || heap->map_ptr);
+
+    if (!resource->map_count)
+    {
+        if (!heap->map_ptr)
+        {
+            const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+            TRACE("Mapping heap %p.\n", heap);
+
+            assert(!heap->map_count);
+
+            if ((vr = VK_CALL(vkMapMemory(device->vk_device, heap->vk_memory,
+                    0, VK_WHOLE_SIZE, 0, &heap->map_ptr))) < 0)
+            {
+                WARN("Failed to map device memory, vr %d.\n", vr);
+                heap->map_ptr = NULL;
+            }
+
+            hr = hresult_from_vk_result(vr);
+        }
+
+        if (heap->map_ptr)
+            ++heap->map_count;
+    }
+
+    if (hr == S_OK)
+    {
+        assert(heap->map_ptr);
+        if (data)
+            *data = (BYTE *)heap->map_ptr + offset;
+        ++resource->map_count;
+    }
+    else
+    {
+        assert(!heap->map_ptr);
+        if (data)
+            *data = NULL;
+    }
+
+    pthread_mutex_unlock(&heap->mutex);
+
+    return hr;
+}
+
+static void d3d12_heap_unmap(struct d3d12_heap *heap, struct d3d12_resource *resource)
+{
+    struct d3d12_device *device = heap->device;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&heap->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    if (!resource->map_count)
+    {
+        WARN("Resource %p is not mapped.\n", resource);
+        goto done;
+    }
+
+    --resource->map_count;
+    if (resource->map_count)
+        goto done;
+
+    if (!heap->map_count)
+    {
+        ERR("Heap %p is not mapped.\n", heap);
+        goto done;
+    }
+
+    --heap->map_count;
+    if (!heap->map_count)
+    {
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        TRACE("Unmapping heap %p, ptr %p.\n", heap, heap->map_ptr);
+
+        VK_CALL(vkUnmapMemory(device->vk_device, heap->vk_memory));
+        heap->map_ptr = NULL;
+    }
+
+done:
+    pthread_mutex_unlock(&heap->mutex);
+}
+
+static HRESULT validate_heap_desc(const D3D12_HEAP_DESC *desc, const struct d3d12_resource *resource)
+{
+    if (!resource && !desc->SizeInBytes)
+    {
+        WARN("Invalid size %"PRIu64".\n", desc->SizeInBytes);
+        return E_INVALIDARG;
+    }
+
+    if (desc->Alignment != D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT
+            && desc->Alignment != D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT)
+    {
+        WARN("Invalid alignment %"PRIu64".\n", desc->Alignment);
+        return E_INVALIDARG;
+    }
+
+    if (!resource && desc->Flags & D3D12_HEAP_FLAG_ALLOW_DISPLAY)
+    {
+        WARN("D3D12_HEAP_FLAG_ALLOW_DISPLAY is only for committed resources.\n");
+        return E_INVALIDARG;
+    }
+
+    return S_OK;
+}
+
+static HRESULT d3d12_heap_init(struct d3d12_heap *heap,
+        struct d3d12_device *device, const D3D12_HEAP_DESC *desc, const struct d3d12_resource *resource)
+{
+    VkMemoryRequirements memory_requirements;
+    VkDeviceSize vk_memory_size;
+    HRESULT hr;
+    int rc;
+
+    heap->ID3D12Heap_iface.lpVtbl = &d3d12_heap_vtbl;
+    heap->refcount = 1;
+
+    heap->is_private = !!resource;
+
+    heap->desc = *desc;
+
+    heap->map_ptr = NULL;
+    heap->map_count = 0;
+
+    if (!heap->desc.Properties.CreationNodeMask)
+        heap->desc.Properties.CreationNodeMask = 1;
+    if (!heap->desc.Properties.VisibleNodeMask)
+        heap->desc.Properties.VisibleNodeMask = 1;
+
+    debug_ignored_node_mask(heap->desc.Properties.CreationNodeMask);
+    debug_ignored_node_mask(heap->desc.Properties.VisibleNodeMask);
+
+    if (!heap->desc.Alignment)
+        heap->desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+
+    if (FAILED(hr = validate_heap_desc(&heap->desc, resource)))
+        return hr;
+
+    if ((rc = pthread_mutex_init(&heap->mutex, NULL)))
+    {
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if (FAILED(hr = vkd3d_private_store_init(&heap->private_store)))
+    {
+        pthread_mutex_destroy(&heap->mutex);
+        return hr;
+    }
+
+    if (resource)
+    {
+        if (d3d12_resource_is_buffer(resource))
+        {
+            hr = vkd3d_allocate_buffer_memory(device, resource->u.vk_buffer,
+                    &heap->desc.Properties, heap->desc.Flags,
+                    &heap->vk_memory, &heap->vk_memory_type, &vk_memory_size);
+        }
+        else
+        {
+            hr = vkd3d_allocate_image_memory(device, resource->u.vk_image,
+                    &heap->desc.Properties, heap->desc.Flags,
+                    &heap->vk_memory, &heap->vk_memory_type, &vk_memory_size);
+        }
+
+        heap->desc.SizeInBytes = vk_memory_size;
+    }
+    else
+    {
+        memory_requirements.size = heap->desc.SizeInBytes;
+        memory_requirements.alignment = heap->desc.Alignment;
+        memory_requirements.memoryTypeBits = ~(uint32_t)0;
+
+        hr = vkd3d_allocate_device_memory(device, &heap->desc.Properties,
+                heap->desc.Flags, &memory_requirements, NULL,
+                &heap->vk_memory, &heap->vk_memory_type);
+    }
+    if (FAILED(hr))
+    {
+        vkd3d_private_store_destroy(&heap->private_store);
+        pthread_mutex_destroy(&heap->mutex);
+        return hr;
+    }
+
+    heap->device = device;
+    if (!heap->is_private)
+        d3d12_device_add_ref(heap->device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_heap_create(struct d3d12_device *device, const D3D12_HEAP_DESC *desc,
+        const struct d3d12_resource *resource, struct d3d12_heap **heap)
+{
+    struct d3d12_heap *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_heap_init(object, device, desc, resource)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created %s %p.\n", object->is_private ? "private heap" : "heap", object);
+
+    *heap = object;
+
+    return S_OK;
+}
+
+static VkImageType vk_image_type_from_d3d12_resource_dimension(D3D12_RESOURCE_DIMENSION dimension)
+{
+    switch (dimension)
+    {
+        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+            return VK_IMAGE_TYPE_1D;
+        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+            return VK_IMAGE_TYPE_2D;
+        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+            return VK_IMAGE_TYPE_3D;
+        default:
+            ERR("Invalid resource dimension %#x.\n", dimension);
+            return VK_IMAGE_TYPE_2D;
+    }
+}
+
+VkSampleCountFlagBits vk_samples_from_sample_count(unsigned int sample_count)
+{
+    switch (sample_count)
+    {
+        case 1:
+            return VK_SAMPLE_COUNT_1_BIT;
+        case 2:
+            return VK_SAMPLE_COUNT_2_BIT;
+        case 4:
+            return VK_SAMPLE_COUNT_4_BIT;
+        case 8:
+            return VK_SAMPLE_COUNT_8_BIT;
+        case 16:
+            return VK_SAMPLE_COUNT_16_BIT;
+        case 32:
+            return VK_SAMPLE_COUNT_32_BIT;
+        case 64:
+            return VK_SAMPLE_COUNT_64_BIT;
+        default:
+            return 0;
+    }
+}
+
+VkSampleCountFlagBits vk_samples_from_dxgi_sample_desc(const DXGI_SAMPLE_DESC *desc)
+{
+    VkSampleCountFlagBits vk_samples;
+
+    if ((vk_samples = vk_samples_from_sample_count(desc->Count)))
+        return vk_samples;
+
+    FIXME("Unhandled sample count %u.\n", desc->Count);
+    return VK_SAMPLE_COUNT_1_BIT;
+}
+
+HRESULT vkd3d_create_buffer(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, VkBuffer *vk_buffer)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    const bool sparse_resource = !heap_properties;
+    VkBufferCreateInfo buffer_info;
+    D3D12_HEAP_TYPE heap_type;
+    VkResult vr;
+
+    heap_type = heap_properties ? heap_properties->Type : D3D12_HEAP_TYPE_DEFAULT;
+
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.pNext = NULL;
+    buffer_info.flags = 0;
+    buffer_info.size = desc->Width;
+
+    if (sparse_resource)
+    {
+        buffer_info.flags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
+        if (device->vk_info.sparse_properties.residencyNonResidentStrict)
+            buffer_info.flags |= VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT;
+    }
+
+    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+            | VK_BUFFER_USAGE_TRANSFER_DST_BIT
+            | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+            | VK_BUFFER_USAGE_INDEX_BUFFER_BIT
+            | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
+            | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
+
+    if (device->vk_info.EXT_conditional_rendering)
+        buffer_info.usage |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
+
+    if (heap_type == D3D12_HEAP_TYPE_DEFAULT && device->vk_info.EXT_transform_feedback)
+    {
+        buffer_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT
+                | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
+    }
+
+    if (heap_type == D3D12_HEAP_TYPE_UPLOAD)
+        buffer_info.usage &= ~VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+    else if (heap_type == D3D12_HEAP_TYPE_READBACK)
+        buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
+        buffer_info.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+    if (!(desc->Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE))
+        buffer_info.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+
+    /* Buffers always have properties of D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS. */
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS)
+    {
+        WARN("D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS cannot be set for buffers.\n");
+        return E_INVALIDARG;
+    }
+
+    if (device->queue_family_count > 1)
+    {
+        buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
+        buffer_info.queueFamilyIndexCount = device->queue_family_count;
+        buffer_info.pQueueFamilyIndices = device->queue_family_indices;
+    }
+    else
+    {
+        buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+        buffer_info.queueFamilyIndexCount = 0;
+        buffer_info.pQueueFamilyIndices = NULL;
+    }
+
+    if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
+        FIXME("Unsupported resource flags %#x.\n", desc->Flags);
+
+    if ((vr = VK_CALL(vkCreateBuffer(device->vk_device, &buffer_info, NULL, vk_buffer))) < 0)
+    {
+        WARN("Failed to create Vulkan buffer, vr %d.\n", vr);
+        *vk_buffer = VK_NULL_HANDLE;
+    }
+
+    return hresult_from_vk_result(vr);
+}
+
+static unsigned int max_miplevel_count(const D3D12_RESOURCE_DESC *desc)
+{
+    unsigned int size = max(desc->Width, desc->Height);
+    size = max(size, d3d12_resource_desc_get_depth(desc, 0));
+    return vkd3d_log2i(size) + 1;
+}
+
+static const struct vkd3d_format_compatibility_list *vkd3d_get_format_compatibility_list(
+        const struct d3d12_device *device, DXGI_FORMAT dxgi_format)
+{
+    unsigned int i;
+
+    for (i = 0; i < device->format_compatibility_list_count; ++i)
+    {
+        if (device->format_compatibility_lists[i].typeless_format == dxgi_format)
+            return &device->format_compatibility_lists[i];
+    }
+
+    return NULL;
+}
+
+static bool vkd3d_is_linear_tiling_supported(const struct d3d12_device *device, VkImageCreateInfo *image_info)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkImageFormatProperties properties;
+    VkResult vr;
+
+    if ((vr = VK_CALL(vkGetPhysicalDeviceImageFormatProperties(device->vk_physical_device, image_info->format,
+            image_info->imageType, VK_IMAGE_TILING_LINEAR, image_info->usage, image_info->flags, &properties))) < 0)
+    {
+        if (vr != VK_ERROR_FORMAT_NOT_SUPPORTED)
+            WARN("Failed to get device image format properties, vr %d.\n", vr);
+
+        return false;
+    }
+
+    return image_info->extent.depth <= properties.maxExtent.depth
+            && image_info->mipLevels <= properties.maxMipLevels
+            && image_info->arrayLayers <= properties.maxArrayLayers
+            && (image_info->samples & properties.sampleCounts);
+}
+
+static HRESULT vkd3d_create_image(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, struct d3d12_resource *resource, VkImage *vk_image)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    const struct vkd3d_format_compatibility_list *compat_list;
+    const bool sparse_resource = !heap_properties;
+    VkImageFormatListCreateInfoKHR format_list;
+    const struct vkd3d_format *format;
+    VkImageCreateInfo image_info;
+    VkResult vr;
+
+    if (!(format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0)))
+    {
+        WARN("Invalid DXGI format %#x.\n", desc->Format);
+        return E_INVALIDARG;
+    }
+
+    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_info.pNext = NULL;
+    image_info.flags = 0;
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
+    {
+        /* Format compatibility rules are more relaxed for UAVs. */
+        if (format->type != VKD3D_FORMAT_TYPE_UINT)
+            image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+    }
+    else if (!(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) && format->type == VKD3D_FORMAT_TYPE_TYPELESS)
+    {
+        image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+        if ((compat_list = vkd3d_get_format_compatibility_list(device, desc->Format)))
+        {
+            format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+            format_list.pNext = NULL;
+            format_list.viewFormatCount = compat_list->format_count;
+            format_list.pViewFormats = compat_list->vk_formats;
+
+            image_info.pNext = &format_list;
+        }
+    }
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
+            && desc->Width == desc->Height && desc->DepthOrArraySize >= 6
+            && desc->SampleDesc.Count == 1)
+        image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
+        image_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR;
+
+    if (sparse_resource)
+    {
+        image_info.flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
+        if (device->vk_info.sparse_properties.residencyNonResidentStrict)
+            image_info.flags |= VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
+    }
+
+    image_info.imageType = vk_image_type_from_d3d12_resource_dimension(desc->Dimension);
+    image_info.format = format->vk_format;
+    image_info.extent.width = desc->Width;
+    image_info.extent.height = desc->Height;
+
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
+    {
+        image_info.extent.depth = desc->DepthOrArraySize;
+        image_info.arrayLayers = 1;
+    }
+    else
+    {
+        image_info.extent.depth = 1;
+        image_info.arrayLayers = desc->DepthOrArraySize;
+    }
+
+    image_info.mipLevels = min(desc->MipLevels, max_miplevel_count(desc));
+    image_info.samples = vk_samples_from_dxgi_sample_desc(&desc->SampleDesc);
+
+    if (sparse_resource)
+    {
+        if (desc->Layout != D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE)
+        {
+            WARN("D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE must be used for reserved texture.\n");
+            return E_INVALIDARG;
+        }
+
+        image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    }
+    else if (desc->Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN)
+    {
+        image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    }
+    else if (desc->Layout == D3D12_TEXTURE_LAYOUT_ROW_MAJOR)
+    {
+        image_info.tiling = VK_IMAGE_TILING_LINEAR;
+    }
+    else
+    {
+        FIXME("Unsupported layout %#x.\n", desc->Layout);
+        return E_NOTIMPL;
+    }
+
+    image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
+        image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
+        image_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+    if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
+        image_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+    if (!(desc->Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE))
+        image_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+
+    if ((desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS) && device->queue_family_count > 1)
+    {
+        TRACE("Creating image with VK_SHARING_MODE_CONCURRENT.\n");
+        image_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
+        image_info.queueFamilyIndexCount = device->queue_family_count;
+        image_info.pQueueFamilyIndices = device->queue_family_indices;
+    }
+    else
+    {
+        image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+        image_info.queueFamilyIndexCount = 0;
+        image_info.pQueueFamilyIndices = NULL;
+    }
+
+    if (heap_properties && is_cpu_accessible_heap(heap_properties))
+    {
+        image_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+
+        if (vkd3d_is_linear_tiling_supported(device, &image_info))
+        {
+            /* Required for ReadFromSubresource(). */
+            WARN("Forcing VK_IMAGE_TILING_LINEAR for CPU readable texture.\n");
+            image_info.tiling = VK_IMAGE_TILING_LINEAR;
+        }
+    }
+    else
+    {
+        image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    }
+
+    if (resource && image_info.tiling == VK_IMAGE_TILING_LINEAR)
+        resource->flags |= VKD3D_RESOURCE_LINEAR_TILING;
+
+    if ((vr = VK_CALL(vkCreateImage(device->vk_device, &image_info, NULL, vk_image))) < 0)
+        WARN("Failed to create Vulkan image, vr %d.\n", vr);
+
+    return hresult_from_vk_result(vr);
+}
+
+HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info)
+{
+    static const D3D12_HEAP_PROPERTIES heap_properties = {D3D12_HEAP_TYPE_DEFAULT};
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    D3D12_RESOURCE_DESC validated_desc;
+    VkMemoryRequirements requirements;
+    VkImage vk_image;
+    HRESULT hr;
+
+    assert(desc->Dimension != D3D12_RESOURCE_DIMENSION_BUFFER);
+    assert(d3d12_resource_validate_desc(desc, device) == S_OK);
+
+    if (!desc->MipLevels)
+    {
+        validated_desc = *desc;
+        validated_desc.MipLevels = max_miplevel_count(desc);
+        desc = &validated_desc;
+    }
+
+    /* XXX: We have to create an image to get its memory requirements. */
+    if (SUCCEEDED(hr = vkd3d_create_image(device, &heap_properties, 0, desc, NULL, &vk_image)))
+    {
+        VK_CALL(vkGetImageMemoryRequirements(device->vk_device, vk_image, &requirements));
+        VK_CALL(vkDestroyImage(device->vk_device, vk_image, NULL));
+
+        allocation_info->SizeInBytes = requirements.size;
+        allocation_info->Alignment = requirements.alignment;
+    }
+
+    return hr;
+}
+
+static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    if (resource->flags & VKD3D_RESOURCE_EXTERNAL)
+        return;
+
+    if (resource->gpu_address)
+        vkd3d_gpu_va_allocator_free(&device->gpu_va_allocator, resource->gpu_address);
+
+    if (d3d12_resource_is_buffer(resource))
+        VK_CALL(vkDestroyBuffer(device->vk_device, resource->u.vk_buffer, NULL));
+    else
+        VK_CALL(vkDestroyImage(device->vk_device, resource->u.vk_image, NULL));
+
+    if (resource->flags & VKD3D_RESOURCE_DEDICATED_HEAP)
+        d3d12_heap_destroy(resource->heap);
+}
+
+static ULONG d3d12_resource_incref(struct d3d12_resource *resource)
+{
+    ULONG refcount = InterlockedIncrement(&resource->internal_refcount);
+
+    TRACE("%p increasing refcount to %u.\n", resource, refcount);
+
+    return refcount;
+}
+
+static ULONG d3d12_resource_decref(struct d3d12_resource *resource)
+{
+    ULONG refcount = InterlockedDecrement(&resource->internal_refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", resource, refcount);
+
+    if (!refcount)
+    {
+        vkd3d_private_store_destroy(&resource->private_store);
+        d3d12_resource_destroy(resource, resource->device);
+        vkd3d_free(resource);
+    }
+
+    return refcount;
+}
+
+bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource)
+{
+    return resource->heap && is_cpu_accessible_heap(&resource->heap->desc.Properties);
+}
+
+static bool d3d12_resource_validate_box(const struct d3d12_resource *resource,
+        unsigned int sub_resource_idx, const D3D12_BOX *box)
+{
+    unsigned int mip_level = sub_resource_idx % resource->desc.MipLevels;
+    struct d3d12_device *device = resource->device;
+    const struct vkd3d_format *vkd3d_format;
+    uint32_t width_mask, height_mask;
+    uint64_t width, height, depth;
+
+    width = d3d12_resource_desc_get_width(&resource->desc, mip_level);
+    height = d3d12_resource_desc_get_height(&resource->desc, mip_level);
+    depth = d3d12_resource_desc_get_depth(&resource->desc, mip_level);
+
+    vkd3d_format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, 0);
+    assert(vkd3d_format);
+    width_mask = vkd3d_format->block_width - 1;
+    height_mask = vkd3d_format->block_height - 1;
+
+    return box->left <= width && box->right <= width
+            && box->top <= height && box->bottom <= height
+            && box->front <= depth && box->back <= depth
+            && !(box->left & width_mask)
+            && !(box->right & width_mask)
+            && !(box->top & height_mask)
+            && !(box->bottom & height_mask);
+}
+
+static void d3d12_resource_get_level_box(const struct d3d12_resource *resource,
+        unsigned int level, D3D12_BOX *box)
+{
+    box->left = 0;
+    box->top = 0;
+    box->front = 0;
+    box->right = d3d12_resource_desc_get_width(&resource->desc, level);
+    box->bottom = d3d12_resource_desc_get_height(&resource->desc, level);
+    box->back = d3d12_resource_desc_get_depth(&resource->desc, level);
+}
+
+/* ID3D12Resource */
+static inline struct d3d12_resource *impl_from_ID3D12Resource(ID3D12Resource *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_resource, ID3D12Resource_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_QueryInterface(ID3D12Resource *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12Resource)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12Resource_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_resource_AddRef(ID3D12Resource *iface)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    ULONG refcount = InterlockedIncrement(&resource->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", resource, refcount);
+
+    if (refcount == 1)
+    {
+        struct d3d12_device *device = resource->device;
+
+        d3d12_device_add_ref(device);
+        d3d12_resource_incref(resource);
+    }
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_resource_Release(ID3D12Resource *iface)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    ULONG refcount = InterlockedDecrement(&resource->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", resource, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = resource->device;
+
+        d3d12_resource_decref(resource);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_GetPrivateData(ID3D12Resource *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&resource->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_SetPrivateData(ID3D12Resource *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&resource->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_SetPrivateDataInterface(ID3D12Resource *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&resource->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_SetName(ID3D12Resource *iface, const WCHAR *name)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    HRESULT hr;
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, resource->device->wchar_size));
+
+    if (resource->flags & VKD3D_RESOURCE_DEDICATED_HEAP)
+    {
+        if (FAILED(hr = d3d12_heap_SetName(&resource->heap->ID3D12Heap_iface, name)))
+            return hr;
+    }
+
+    if (d3d12_resource_is_buffer(resource))
+        return vkd3d_set_vk_object_name(resource->device, (uint64_t)resource->u.vk_buffer,
+                VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, name);
+    else
+        return vkd3d_set_vk_object_name(resource->device, (uint64_t)resource->u.vk_image,
+                VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, name);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_GetDevice(ID3D12Resource *iface, REFIID iid, void **device)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(resource->device, iid, device);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_Map(ID3D12Resource *iface, UINT sub_resource,
+        const D3D12_RANGE *read_range, void **data)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    unsigned int sub_resource_count;
+    HRESULT hr;
+
+    TRACE("iface %p, sub_resource %u, read_range %p, data %p.\n",
+            iface, sub_resource, read_range, data);
+
+    if (!d3d12_resource_is_cpu_accessible(resource))
+    {
+        WARN("Resource is not CPU accessible.\n");
+        return E_INVALIDARG;
+    }
+
+    sub_resource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
+    if (sub_resource >= sub_resource_count)
+    {
+        WARN("Sub-resource index %u is out of range (%u sub-resources).\n", sub_resource, sub_resource_count);
+        return E_INVALIDARG;
+    }
+
+    if (d3d12_resource_is_texture(resource))
+    {
+        /* Textures seem to be mappable only on UMA adapters. */
+        FIXME("Not implemented for textures.\n");
+        return E_INVALIDARG;
+    }
+
+    if (!resource->heap)
+    {
+        FIXME("Not implemented for this resource type.\n");
+        return E_NOTIMPL;
+    }
+
+    WARN("Ignoring read range %p.\n", read_range);
+
+    if (FAILED(hr = d3d12_heap_map(resource->heap, resource->heap_offset, resource, data)))
+        WARN("Failed to map resource %p, hr %#x.\n", resource, hr);
+
+    if (data)
+        TRACE("Returning pointer %p.\n", *data);
+
+    return hr;
+}
+
+static void STDMETHODCALLTYPE d3d12_resource_Unmap(ID3D12Resource *iface, UINT sub_resource,
+        const D3D12_RANGE *written_range)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    unsigned int sub_resource_count;
+
+    TRACE("iface %p, sub_resource %u, written_range %p.\n",
+            iface, sub_resource, written_range);
+
+    sub_resource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
+    if (sub_resource >= sub_resource_count)
+    {
+        WARN("Sub-resource index %u is out of range (%u sub-resources).\n", sub_resource, sub_resource_count);
+        return;
+    }
+
+    WARN("Ignoring written range %p.\n", written_range);
+
+    d3d12_heap_unmap(resource->heap, resource);
+}
+
+static D3D12_RESOURCE_DESC * STDMETHODCALLTYPE d3d12_resource_GetDesc(ID3D12Resource *iface,
+        D3D12_RESOURCE_DESC *resource_desc)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p, resource_desc %p.\n", iface, resource_desc);
+
+    *resource_desc = resource->desc;
+    return resource_desc;
+}
+
+static D3D12_GPU_VIRTUAL_ADDRESS STDMETHODCALLTYPE d3d12_resource_GetGPUVirtualAddress(ID3D12Resource *iface)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return resource->gpu_address;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_WriteToSubresource(ID3D12Resource *iface,
+        UINT dst_sub_resource, const D3D12_BOX *dst_box, const void *src_data,
+        UINT src_row_pitch, UINT src_slice_pitch)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkImageSubresource vk_sub_resource;
+    const struct vkd3d_format *format;
+    VkSubresourceLayout vk_layout;
+    struct d3d12_device *device;
+    uint8_t *dst_data;
+    D3D12_BOX box;
+    HRESULT hr;
+
+    TRACE("iface %p, src_data %p, src_row_pitch %u, src_slice_pitch %u, "
+            "dst_sub_resource %u, dst_box %s.\n",
+            iface, src_data, src_row_pitch, src_slice_pitch, dst_sub_resource, debug_d3d12_box(dst_box));
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        WARN("Buffers are not supported.\n");
+        return E_INVALIDARG;
+    }
+
+    device = resource->device;
+    vk_procs = &device->vk_procs;
+
+    if (!(format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, 0)))
+    {
+        ERR("Invalid DXGI format %#x.\n", resource->desc.Format);
+        return E_INVALIDARG;
+    }
+    if (format->vk_aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT)
+    {
+        FIXME("Not supported for format %#x.\n", format->dxgi_format);
+        return E_NOTIMPL;
+    }
+
+    vk_sub_resource.arrayLayer = dst_sub_resource / resource->desc.MipLevels;
+    vk_sub_resource.mipLevel = dst_sub_resource % resource->desc.MipLevels;
+    vk_sub_resource.aspectMask = format->vk_aspect_mask;
+
+    if (!dst_box)
+    {
+        d3d12_resource_get_level_box(resource, vk_sub_resource.mipLevel, &box);
+        dst_box = &box;
+    }
+    else if (!d3d12_resource_validate_box(resource, dst_sub_resource, dst_box))
+    {
+        WARN("Invalid box %s.\n", debug_d3d12_box(dst_box));
+        return E_INVALIDARG;
+    }
+
+    if (d3d12_box_is_empty(dst_box))
+    {
+        WARN("Empty box %s.\n", debug_d3d12_box(dst_box));
+        return S_OK;
+    }
+
+    if (!d3d12_resource_is_cpu_accessible(resource))
+    {
+        FIXME_ONCE("Not implemented for this resource type.\n");
+        return E_NOTIMPL;
+    }
+    if (!(resource->flags & VKD3D_RESOURCE_LINEAR_TILING))
+    {
+        FIXME_ONCE("Not implemented for image tiling other than VK_IMAGE_TILING_LINEAR.\n");
+        return E_NOTIMPL;
+    }
+
+    VK_CALL(vkGetImageSubresourceLayout(device->vk_device, resource->u.vk_image, &vk_sub_resource, &vk_layout));
+    TRACE("Offset %#"PRIx64", size %#"PRIx64", row pitch %#"PRIx64", depth pitch %#"PRIx64".\n",
+            vk_layout.offset, vk_layout.size, vk_layout.rowPitch, vk_layout.depthPitch);
+
+    if (FAILED(hr = d3d12_heap_map(resource->heap, resource->heap_offset, resource, (void **)&dst_data)))
+    {
+        WARN("Failed to map resource %p, hr %#x.\n", resource, hr);
+        return hr;
+    }
+
+    dst_data += vk_layout.offset + vkd3d_format_get_data_offset(format, vk_layout.rowPitch,
+            vk_layout.depthPitch, dst_box->left, dst_box->top, dst_box->front);
+
+    vkd3d_format_copy_data(format, src_data, src_row_pitch, src_slice_pitch,
+            dst_data, vk_layout.rowPitch, vk_layout.depthPitch, dst_box->right - dst_box->left,
+            dst_box->bottom - dst_box->top, dst_box->back - dst_box->front);
+
+    d3d12_heap_unmap(resource->heap, resource);
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_ReadFromSubresource(ID3D12Resource *iface,
+        void *dst_data, UINT dst_row_pitch, UINT dst_slice_pitch,
+        UINT src_sub_resource, const D3D12_BOX *src_box)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    VkImageSubresource vk_sub_resource;
+    const struct vkd3d_format *format;
+    VkSubresourceLayout vk_layout;
+    struct d3d12_device *device;
+    uint8_t *src_data;
+    D3D12_BOX box;
+    HRESULT hr;
+
+    TRACE("iface %p, dst_data %p, dst_row_pitch %u, dst_slice_pitch %u, "
+            "src_sub_resource %u, src_box %s.\n",
+            iface, dst_data, dst_row_pitch, dst_slice_pitch, src_sub_resource, debug_d3d12_box(src_box));
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        WARN("Buffers are not supported.\n");
+        return E_INVALIDARG;
+    }
+
+    device = resource->device;
+    vk_procs = &device->vk_procs;
+
+    if (!(format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, 0)))
+    {
+        ERR("Invalid DXGI format %#x.\n", resource->desc.Format);
+        return E_INVALIDARG;
+    }
+    if (format->vk_aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT)
+    {
+        FIXME("Not supported for format %#x.\n", format->dxgi_format);
+        return E_NOTIMPL;
+    }
+
+    vk_sub_resource.arrayLayer = src_sub_resource / resource->desc.MipLevels;
+    vk_sub_resource.mipLevel = src_sub_resource % resource->desc.MipLevels;
+    vk_sub_resource.aspectMask = format->vk_aspect_mask;
+
+    if (!src_box)
+    {
+        d3d12_resource_get_level_box(resource, vk_sub_resource.mipLevel, &box);
+        src_box = &box;
+    }
+    else if (!d3d12_resource_validate_box(resource, src_sub_resource, src_box))
+    {
+        WARN("Invalid box %s.\n", debug_d3d12_box(src_box));
+        return E_INVALIDARG;
+    }
+
+    if (d3d12_box_is_empty(src_box))
+    {
+        WARN("Empty box %s.\n", debug_d3d12_box(src_box));
+        return S_OK;
+    }
+
+    if (!d3d12_resource_is_cpu_accessible(resource))
+    {
+        FIXME_ONCE("Not implemented for this resource type.\n");
+        return E_NOTIMPL;
+    }
+    if (!(resource->flags & VKD3D_RESOURCE_LINEAR_TILING))
+    {
+        FIXME_ONCE("Not implemented for image tiling other than VK_IMAGE_TILING_LINEAR.\n");
+        return E_NOTIMPL;
+    }
+
+    VK_CALL(vkGetImageSubresourceLayout(device->vk_device, resource->u.vk_image, &vk_sub_resource, &vk_layout));
+    TRACE("Offset %#"PRIx64", size %#"PRIx64", row pitch %#"PRIx64", depth pitch %#"PRIx64".\n",
+            vk_layout.offset, vk_layout.size, vk_layout.rowPitch, vk_layout.depthPitch);
+
+    if (FAILED(hr = d3d12_heap_map(resource->heap, resource->heap_offset, resource, (void **)&src_data)))
+    {
+        WARN("Failed to map resource %p, hr %#x.\n", resource, hr);
+        return hr;
+    }
+
+    src_data += vk_layout.offset + vkd3d_format_get_data_offset(format, vk_layout.rowPitch,
+            vk_layout.depthPitch, src_box->left, src_box->top, src_box->front);
+
+    vkd3d_format_copy_data(format, src_data, vk_layout.rowPitch, vk_layout.depthPitch,
+            dst_data, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
+            src_box->bottom - src_box->top, src_box->back - src_box->front);
+
+    d3d12_heap_unmap(resource->heap, resource);
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_resource_GetHeapProperties(ID3D12Resource *iface,
+        D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS *flags)
+{
+    struct d3d12_resource *resource = impl_from_ID3D12Resource(iface);
+    struct d3d12_heap *heap;
+
+    TRACE("iface %p, heap_properties %p, flags %p.\n",
+            iface, heap_properties, flags);
+
+    if (resource->flags & VKD3D_RESOURCE_EXTERNAL)
+    {
+        if (heap_properties)
+        {
+            memset(heap_properties, 0, sizeof(*heap_properties));
+            heap_properties->Type = D3D12_HEAP_TYPE_DEFAULT;
+            heap_properties->CreationNodeMask = 1;
+            heap_properties->VisibleNodeMask = 1;
+        }
+        if (flags)
+            *flags = D3D12_HEAP_FLAG_NONE;
+        return S_OK;
+    }
+
+    if (!(heap = resource->heap))
+    {
+        WARN("Cannot get heap properties for reserved resources.\n");
+        return E_INVALIDARG;
+    }
+
+    if (heap_properties)
+        *heap_properties = heap->desc.Properties;
+    if (flags)
+        *flags = heap->desc.Flags;
+
+    return S_OK;
+}
+
+static const struct ID3D12ResourceVtbl d3d12_resource_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_resource_QueryInterface,
+    d3d12_resource_AddRef,
+    d3d12_resource_Release,
+    /* ID3D12Object methods */
+    d3d12_resource_GetPrivateData,
+    d3d12_resource_SetPrivateData,
+    d3d12_resource_SetPrivateDataInterface,
+    d3d12_resource_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_resource_GetDevice,
+    /* ID3D12Resource methods */
+    d3d12_resource_Map,
+    d3d12_resource_Unmap,
+    d3d12_resource_GetDesc,
+    d3d12_resource_GetGPUVirtualAddress,
+    d3d12_resource_WriteToSubresource,
+    d3d12_resource_ReadFromSubresource,
+    d3d12_resource_GetHeapProperties,
+};
+
+struct d3d12_resource *unsafe_impl_from_ID3D12Resource(ID3D12Resource *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_resource_vtbl);
+    return impl_from_ID3D12Resource(iface);
+}
+
+static void d3d12_validate_resource_flags(D3D12_RESOURCE_FLAGS flags)
+{
+    unsigned int unknown_flags = flags & ~(D3D12_RESOURCE_FLAG_NONE
+            | D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET
+            | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
+            | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS
+            | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE
+            | D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER
+            | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS);
+
+    if (unknown_flags)
+        FIXME("Unknown resource flags %#x.\n", unknown_flags);
+    if (flags & D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER)
+        FIXME("Ignoring D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER.\n");
+}
+
+static bool d3d12_resource_validate_texture_format(const D3D12_RESOURCE_DESC *desc,
+        const struct vkd3d_format *format)
+{
+    if (!vkd3d_format_is_compressed(format))
+        return true;
+
+    if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D && format->block_height > 1)
+    {
+        WARN("1D texture with a format block height > 1.\n");
+        return false;
+    }
+
+    if (align(desc->Width, format->block_width) != desc->Width
+            || align(desc->Height, format->block_height) != desc->Height)
+    {
+        WARN("Invalid size %"PRIu64"x%u for block compressed format %#x.\n",
+                desc->Width, desc->Height, desc->Format);
+        return false;
+    }
+
+    return true;
+}
+
+static bool d3d12_resource_validate_texture_alignment(const D3D12_RESOURCE_DESC *desc,
+        const struct vkd3d_format *format)
+{
+    uint64_t estimated_size;
+
+    if (!desc->Alignment)
+        return true;
+
+    if (desc->Alignment != D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT
+            && desc->Alignment != D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
+            && (desc->SampleDesc.Count == 1 || desc->Alignment != D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT))
+    {
+        WARN("Invalid resource alignment %#"PRIx64".\n", desc->Alignment);
+        return false;
+    }
+
+    if (desc->Alignment < D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
+    {
+        /* Windows uses the slice size to determine small alignment eligibility. DepthOrArraySize is ignored. */
+        estimated_size = desc->Width * desc->Height * format->byte_count * format->block_byte_count
+                / (format->block_width * format->block_height);
+        if (estimated_size > D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
+        {
+            WARN("Invalid resource alignment %#"PRIx64" (required %#x).\n",
+                    desc->Alignment, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
+            return false;
+        }
+    }
+
+    /* The size check for MSAA textures with D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT is probably
+     * not important. The 4MB requirement is no longer universal and Vulkan has no such requirement. */
+
+    return true;
+}
+
+HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device)
+{
+    const struct vkd3d_format *format;
+
+    switch (desc->Dimension)
+    {
+        case D3D12_RESOURCE_DIMENSION_BUFFER:
+            if (desc->MipLevels != 1)
+            {
+                WARN("Invalid miplevel count %u for buffer.\n", desc->MipLevels);
+                return E_INVALIDARG;
+            }
+
+            if (desc->Format != DXGI_FORMAT_UNKNOWN || desc->Layout != D3D12_TEXTURE_LAYOUT_ROW_MAJOR
+                    || desc->Height != 1 || desc->DepthOrArraySize != 1
+                    || desc->SampleDesc.Count != 1 || desc->SampleDesc.Quality != 0
+                    || (desc->Alignment != 0 && desc->Alignment != D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT))
+            {
+                WARN("Invalid parameters for a buffer resource.\n");
+                return E_INVALIDARG;
+            }
+            break;
+
+        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+            if (desc->Height != 1)
+            {
+                WARN("1D texture with a height of %u.\n", desc->Height);
+                return E_INVALIDARG;
+            }
+            /* Fall through. */
+        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+            if (!(format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0)))
+            {
+                WARN("Invalid format %#x.\n", desc->Format);
+                return E_INVALIDARG;
+            }
+
+            if (!d3d12_resource_validate_texture_format(desc, format)
+                    || !d3d12_resource_validate_texture_alignment(desc, format))
+                return E_INVALIDARG;
+            break;
+
+        default:
+            WARN("Invalid resource dimension %#x.\n", desc->Dimension);
+            return E_INVALIDARG;
+    }
+
+    d3d12_validate_resource_flags(desc->Flags);
+
+    return S_OK;
+}
+
+static bool d3d12_resource_validate_heap_properties(const struct d3d12_resource *resource,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_RESOURCE_STATES initial_state)
+{
+    if (heap_properties->Type == D3D12_HEAP_TYPE_UPLOAD
+            || heap_properties->Type == D3D12_HEAP_TYPE_READBACK)
+    {
+        if (d3d12_resource_is_texture(resource))
+        {
+            WARN("Textures cannot be created on upload/readback heaps.\n");
+            return false;
+        }
+
+        if (resource->desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
+        {
+            WARN("Render target and unordered access buffers cannot be created on upload/readback heaps.\n");
+            return false;
+        }
+    }
+
+    if (heap_properties->Type == D3D12_HEAP_TYPE_UPLOAD && initial_state != D3D12_RESOURCE_STATE_GENERIC_READ)
+    {
+        WARN("For D3D12_HEAP_TYPE_UPLOAD the state must be D3D12_RESOURCE_STATE_GENERIC_READ.\n");
+        return false;
+    }
+    if (heap_properties->Type == D3D12_HEAP_TYPE_READBACK && initial_state != D3D12_RESOURCE_STATE_COPY_DEST)
+    {
+        WARN("For D3D12_HEAP_TYPE_READBACK the state must be D3D12_RESOURCE_STATE_COPY_DEST.\n");
+        return false;
+    }
+
+    return true;
+}
+
+static HRESULT d3d12_resource_init(struct d3d12_resource *resource, struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value)
+{
+    HRESULT hr;
+
+    resource->ID3D12Resource_iface.lpVtbl = &d3d12_resource_vtbl;
+    resource->refcount = 1;
+    resource->internal_refcount = 1;
+
+    resource->desc = *desc;
+
+    if (heap_properties && !d3d12_resource_validate_heap_properties(resource, heap_properties, initial_state))
+        return E_INVALIDARG;
+
+    if (!is_valid_resource_state(initial_state))
+    {
+        WARN("Invalid initial resource state %#x.\n", initial_state);
+        return E_INVALIDARG;
+    }
+
+    if (optimized_clear_value && d3d12_resource_is_buffer(resource))
+    {
+        WARN("Optimized clear value must be NULL for buffers.\n");
+        return E_INVALIDARG;
+    }
+
+    if (optimized_clear_value)
+        WARN("Ignoring optimized clear value.\n");
+
+    resource->gpu_address = 0;
+    resource->flags = 0;
+
+    if (FAILED(hr = d3d12_resource_validate_desc(&resource->desc, device)))
+        return hr;
+
+    switch (desc->Dimension)
+    {
+        case D3D12_RESOURCE_DIMENSION_BUFFER:
+            if (FAILED(hr = vkd3d_create_buffer(device, heap_properties, heap_flags,
+                    &resource->desc, &resource->u.vk_buffer)))
+                return hr;
+            if (!(resource->gpu_address = vkd3d_gpu_va_allocator_allocate(&device->gpu_va_allocator,
+                    desc->Alignment ? desc->Alignment : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
+                    desc->Width, resource)))
+            {
+                ERR("Failed to allocate GPU VA.\n");
+                d3d12_resource_destroy(resource, device);
+                return E_OUTOFMEMORY;
+            }
+            break;
+
+        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+            if (!resource->desc.MipLevels)
+                resource->desc.MipLevels = max_miplevel_count(desc);
+            resource->flags |= VKD3D_RESOURCE_INITIAL_STATE_TRANSITION;
+            if (FAILED(hr = vkd3d_create_image(device, heap_properties, heap_flags,
+                    &resource->desc, resource, &resource->u.vk_image)))
+                return hr;
+            break;
+
+        default:
+            WARN("Invalid resource dimension %#x.\n", resource->desc.Dimension);
+            return E_INVALIDARG;
+    }
+
+    resource->map_count = 0;
+
+    resource->initial_state = initial_state;
+
+    resource->heap = NULL;
+    resource->heap_offset = 0;
+
+    if (FAILED(hr = vkd3d_private_store_init(&resource->private_store)))
+    {
+        d3d12_resource_destroy(resource, device);
+        return hr;
+    }
+
+    d3d12_device_add_ref(resource->device = device);
+
+    return S_OK;
+}
+
+static HRESULT d3d12_resource_create(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
+{
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_resource_init(object, device, heap_properties, heap_flags,
+            desc, initial_state, optimized_clear_value)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    *resource = object;
+
+    return hr;
+}
+
+static HRESULT vkd3d_allocate_resource_memory(
+        struct d3d12_device *device, struct d3d12_resource *resource,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags)
+{
+    D3D12_HEAP_DESC heap_desc;
+    HRESULT hr;
+
+    heap_desc.SizeInBytes = 0;
+    heap_desc.Properties = *heap_properties;
+    heap_desc.Alignment = 0;
+    heap_desc.Flags = heap_flags;
+    if (SUCCEEDED(hr = d3d12_heap_create(device, &heap_desc, resource, &resource->heap)))
+        resource->flags |= VKD3D_RESOURCE_DEDICATED_HEAP;
+    return hr;
+}
+
+HRESULT d3d12_committed_resource_create(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
+{
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    if (!heap_properties)
+    {
+        WARN("Heap properties are NULL.\n");
+        return E_INVALIDARG;
+    }
+
+    if (FAILED(hr = d3d12_resource_create(device, heap_properties, heap_flags,
+            desc, initial_state, optimized_clear_value, &object)))
+        return hr;
+
+    if (FAILED(hr = vkd3d_allocate_resource_memory(device, object, heap_properties, heap_flags)))
+    {
+        d3d12_resource_Release(&object->ID3D12Resource_iface);
+        return hr;
+    }
+
+    TRACE("Created committed resource %p.\n", object);
+
+    *resource = object;
+
+    return S_OK;
+}
+
+static HRESULT vkd3d_bind_heap_memory(struct d3d12_device *device,
+        struct d3d12_resource *resource, struct d3d12_heap *heap, uint64_t heap_offset)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkDevice vk_device = device->vk_device;
+    VkMemoryRequirements requirements;
+    VkResult vr;
+
+    if (d3d12_resource_is_buffer(resource))
+        VK_CALL(vkGetBufferMemoryRequirements(vk_device, resource->u.vk_buffer, &requirements));
+    else
+        VK_CALL(vkGetImageMemoryRequirements(vk_device, resource->u.vk_image, &requirements));
+
+    if (heap_offset % requirements.alignment)
+    {
+        FIXME("Invalid heap offset %#"PRIx64" (alignment %#"PRIx64").\n",
+                heap_offset, requirements.alignment);
+        goto allocate_memory;
+    }
+
+    if (!(requirements.memoryTypeBits & (1u << heap->vk_memory_type)))
+    {
+        FIXME("Memory type %u cannot be bound to resource %p (allowed types %#x).\n",
+                heap->vk_memory_type, resource, requirements.memoryTypeBits);
+        goto allocate_memory;
+    }
+
+    if (d3d12_resource_is_buffer(resource))
+        vr = VK_CALL(vkBindBufferMemory(vk_device, resource->u.vk_buffer, heap->vk_memory, heap_offset));
+    else
+        vr = VK_CALL(vkBindImageMemory(vk_device, resource->u.vk_image, heap->vk_memory, heap_offset));
+
+    if (vr == VK_SUCCESS)
+    {
+        resource->heap = heap;
+        resource->heap_offset = heap_offset;
+    }
+    else
+    {
+        WARN("Failed to bind memory, vr %d.\n", vr);
+    }
+
+    return hresult_from_vk_result(vr);
+
+allocate_memory:
+    FIXME("Allocating device memory.\n");
+    return vkd3d_allocate_resource_memory(device, resource, &heap->desc.Properties, heap->desc.Flags);
+}
+
+HRESULT d3d12_placed_resource_create(struct d3d12_device *device, struct d3d12_heap *heap, uint64_t heap_offset,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
+{
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    if (FAILED(hr = d3d12_resource_create(device, &heap->desc.Properties, heap->desc.Flags,
+            desc, initial_state, optimized_clear_value, &object)))
+        return hr;
+
+    if (FAILED(hr = vkd3d_bind_heap_memory(device, object, heap, heap_offset)))
+    {
+        d3d12_resource_Release(&object->ID3D12Resource_iface);
+        return hr;
+    }
+
+    TRACE("Created placed resource %p.\n", object);
+
+    *resource = object;
+
+    return S_OK;
+}
+
+HRESULT d3d12_reserved_resource_create(struct d3d12_device *device,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
+{
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    if (FAILED(hr = d3d12_resource_create(device, NULL, 0,
+            desc, initial_state, optimized_clear_value, &object)))
+        return hr;
+
+    TRACE("Created reserved resource %p.\n", object);
+
+    *resource = object;
+
+    return S_OK;
+}
+
+HRESULT vkd3d_create_image_resource(ID3D12Device *device,
+        const struct vkd3d_image_resource_create_info *create_info, ID3D12Resource **resource)
+{
+    struct d3d12_device *d3d12_device = unsafe_impl_from_ID3D12Device(device);
+    struct d3d12_resource *object;
+    HRESULT hr;
+
+    TRACE("device %p, create_info %p, resource %p.\n", device, create_info, resource);
+
+    if (!create_info || !resource)
+        return E_INVALIDARG;
+    if (create_info->type != VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO)
+    {
+        WARN("Invalid structure type %#x.\n", create_info->type);
+        return E_INVALIDARG;
+    }
+    if (create_info->next)
+        WARN("Unhandled next %p.\n", create_info->next);
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    memset(object, 0, sizeof(*object));
+
+    object->ID3D12Resource_iface.lpVtbl = &d3d12_resource_vtbl;
+    object->refcount = 1;
+    object->internal_refcount = 1;
+    object->desc = create_info->desc;
+    object->u.vk_image = create_info->vk_image;
+    object->flags = VKD3D_RESOURCE_EXTERNAL;
+    object->flags |= create_info->flags & VKD3D_RESOURCE_PUBLIC_FLAGS;
+    object->initial_state = D3D12_RESOURCE_STATE_COMMON;
+    if (create_info->flags & VKD3D_RESOURCE_PRESENT_STATE_TRANSITION)
+        object->present_state = create_info->present_state;
+    else
+        object->present_state = D3D12_RESOURCE_STATE_COMMON;
+
+    if (FAILED(hr = vkd3d_private_store_init(&object->private_store)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    d3d12_device_add_ref(object->device = d3d12_device);
+
+    TRACE("Created resource %p.\n", object);
+
+    *resource = &object->ID3D12Resource_iface;
+
+    return S_OK;
+}
+
+ULONG vkd3d_resource_incref(ID3D12Resource *resource)
+{
+    TRACE("resource %p.\n", resource);
+    return d3d12_resource_incref(impl_from_ID3D12Resource(resource));
+}
+
+ULONG vkd3d_resource_decref(ID3D12Resource *resource)
+{
+    TRACE("resource %p.\n", resource);
+    return d3d12_resource_decref(impl_from_ID3D12Resource(resource));
+}
+
+/* CBVs, SRVs, UAVs */
+static struct vkd3d_view *vkd3d_view_create(enum vkd3d_view_type type)
+{
+    struct vkd3d_view *view;
+
+    if ((view = vkd3d_malloc(sizeof(*view))))
+    {
+        view->refcount = 1;
+        view->type = type;
+        view->vk_counter_view = VK_NULL_HANDLE;
+    }
+    return view;
+}
+
+void vkd3d_view_incref(struct vkd3d_view *view)
+{
+    InterlockedIncrement(&view->refcount);
+}
+
+static void vkd3d_view_destroy(struct vkd3d_view *view, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    TRACE("Destroying view %p.\n", view);
+
+    switch (view->type)
+    {
+        case VKD3D_VIEW_TYPE_BUFFER:
+            VK_CALL(vkDestroyBufferView(device->vk_device, view->u.vk_buffer_view, NULL));
+            break;
+        case VKD3D_VIEW_TYPE_IMAGE:
+            VK_CALL(vkDestroyImageView(device->vk_device, view->u.vk_image_view, NULL));
+            break;
+        case VKD3D_VIEW_TYPE_SAMPLER:
+            VK_CALL(vkDestroySampler(device->vk_device, view->u.vk_sampler, NULL));
+            break;
+        default:
+            WARN("Unhandled view type %d.\n", view->type);
+    }
+
+    if (view->vk_counter_view)
+        VK_CALL(vkDestroyBufferView(device->vk_device, view->vk_counter_view, NULL));
+
+    vkd3d_free(view);
+}
+
+void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device)
+{
+    if (!InterlockedDecrement(&view->refcount))
+        vkd3d_view_destroy(view, device);
+}
+
+void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src,
+        struct d3d12_device *device)
+{
+    struct d3d12_desc destroy_desc;
+    pthread_mutex_t *mutex;
+
+    destroy_desc.u.view = NULL;
+
+    mutex = d3d12_device_get_descriptor_mutex(device, dst);
+    pthread_mutex_lock(mutex);
+
+    /* Nothing to do for VKD3D_DESCRIPTOR_MAGIC_CBV. */
+    if ((dst->magic == VKD3D_DESCRIPTOR_MAGIC_SRV
+            || dst->magic == VKD3D_DESCRIPTOR_MAGIC_UAV
+            || dst->magic == VKD3D_DESCRIPTOR_MAGIC_SAMPLER)
+            && !InterlockedDecrement(&dst->u.view->refcount))
+        destroy_desc = *dst;
+
+    *dst = *src;
+
+    pthread_mutex_unlock(mutex);
+
+    /* Destroy the view after unlocking to reduce wait time. */
+    if (destroy_desc.u.view)
+        vkd3d_view_destroy(destroy_desc.u.view, device);
+}
+
+static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_device *device)
+{
+    static const struct d3d12_desc null_desc = {0};
+
+    d3d12_desc_write_atomic(descriptor, &null_desc, device);
+}
+
+void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src,
+        struct d3d12_device *device)
+{
+    struct d3d12_desc tmp;
+    pthread_mutex_t *mutex;
+
+    assert(dst != src);
+
+    /* Shadow of the Tomb Raider and possibly other titles sometimes destroy
+     * and rewrite a descriptor in another thread while it is being copied. */
+    mutex = d3d12_device_get_descriptor_mutex(device, src);
+    pthread_mutex_lock(mutex);
+
+    if (src->magic == VKD3D_DESCRIPTOR_MAGIC_SRV
+            || src->magic == VKD3D_DESCRIPTOR_MAGIC_UAV
+            || src->magic == VKD3D_DESCRIPTOR_MAGIC_SAMPLER)
+    {
+        vkd3d_view_incref(src->u.view);
+    }
+
+    tmp = *src;
+
+    pthread_mutex_unlock(mutex);
+
+    d3d12_desc_write_atomic(dst, &tmp, device);
+}
+
+static VkDeviceSize vkd3d_get_required_texel_buffer_alignment(const struct d3d12_device *device,
+        const struct vkd3d_format *format)
+{
+    const VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *properties;
+    const struct vkd3d_vulkan_info *vk_info = &device->vk_info;
+    VkDeviceSize alignment;
+
+    if (vk_info->EXT_texel_buffer_alignment)
+    {
+        properties = &vk_info->texel_buffer_alignment_properties;
+
+        alignment = max(properties->storageTexelBufferOffsetAlignmentBytes,
+                properties->uniformTexelBufferOffsetAlignmentBytes);
+
+        if (properties->storageTexelBufferOffsetSingleTexelAlignment
+                && properties->uniformTexelBufferOffsetSingleTexelAlignment)
+        {
+            assert(!vkd3d_format_is_compressed(format));
+            return min(format->byte_count, alignment);
+        }
+
+        return alignment;
+    }
+
+    return vk_info->device_limits.minTexelBufferOffsetAlignment;
+}
+
+static bool vkd3d_create_vk_buffer_view(struct d3d12_device *device,
+        VkBuffer vk_buffer, const struct vkd3d_format *format,
+        VkDeviceSize offset, VkDeviceSize range, VkBufferView *vk_view)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct VkBufferViewCreateInfo view_desc;
+    VkDeviceSize alignment;
+    VkResult vr;
+
+    if (vkd3d_format_is_compressed(format))
+    {
+        WARN("Invalid format for buffer view %#x.\n", format->dxgi_format);
+        return false;
+    }
+
+    alignment = vkd3d_get_required_texel_buffer_alignment(device, format);
+    if (offset % alignment)
+        FIXME("Offset %#"PRIx64" violates the required alignment %#"PRIx64".\n", offset, alignment);
+
+    view_desc.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
+    view_desc.pNext = NULL;
+    view_desc.flags = 0;
+    view_desc.buffer = vk_buffer;
+    view_desc.format = format->vk_format;
+    view_desc.offset = offset;
+    view_desc.range = range;
+    if ((vr = VK_CALL(vkCreateBufferView(device->vk_device, &view_desc, NULL, vk_view))) < 0)
+        WARN("Failed to create Vulkan buffer view, vr %d.\n", vr);
+    return vr == VK_SUCCESS;
+}
+
+bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, const struct vkd3d_format *format,
+        VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_view *object;
+    VkBufferView vk_view;
+
+    if (!vkd3d_create_vk_buffer_view(device, vk_buffer, format, offset, size, &vk_view))
+        return false;
+
+    if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_BUFFER)))
+    {
+        VK_CALL(vkDestroyBufferView(device->vk_device, vk_view, NULL));
+        return false;
+    }
+
+    object->u.vk_buffer_view = vk_view;
+    object->format = format;
+    object->info.buffer.offset = offset;
+    object->info.buffer.size = size;
+    *view = object;
+    return true;
+}
+
+#define VKD3D_VIEW_RAW_BUFFER 0x1
+
+static bool vkd3d_create_buffer_view_for_resource(struct d3d12_device *device,
+        struct d3d12_resource *resource, DXGI_FORMAT view_format,
+        unsigned int offset, unsigned int size, unsigned int structure_stride,
+        unsigned int flags, struct vkd3d_view **view)
+{
+    const struct vkd3d_format *format;
+    VkDeviceSize element_size;
+
+    if (view_format == DXGI_FORMAT_R32_TYPELESS && (flags & VKD3D_VIEW_RAW_BUFFER))
+    {
+        format = vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+        element_size = format->byte_count;
+    }
+    else if (view_format == DXGI_FORMAT_UNKNOWN && structure_stride)
+    {
+        format = vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+        element_size = structure_stride;
+    }
+    else if ((format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, view_format)))
+    {
+        element_size = format->byte_count;
+    }
+    else
+    {
+        WARN("Failed to find format for %#x.\n", resource->desc.Format);
+        return false;
+    }
+
+    assert(d3d12_resource_is_buffer(resource));
+
+    return vkd3d_create_buffer_view(device, resource->u.vk_buffer,
+            format, offset * element_size, size * element_size, view);
+}
+
+static void vkd3d_set_view_swizzle_for_format(VkComponentMapping *components,
+        const struct vkd3d_format *format, bool allowed_swizzle)
+{
+    components->r = VK_COMPONENT_SWIZZLE_R;
+    components->g = VK_COMPONENT_SWIZZLE_G;
+    components->b = VK_COMPONENT_SWIZZLE_B;
+    components->a = VK_COMPONENT_SWIZZLE_A;
+
+    if (format->vk_aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT)
+    {
+        if (allowed_swizzle)
+        {
+            components->r = VK_COMPONENT_SWIZZLE_ZERO;
+            components->g = VK_COMPONENT_SWIZZLE_R;
+            components->b = VK_COMPONENT_SWIZZLE_ZERO;
+            components->a = VK_COMPONENT_SWIZZLE_ZERO;
+        }
+        else
+        {
+            FIXME("Stencil swizzle is not supported for format %#x.\n",
+                    format->dxgi_format);
+        }
+    }
+
+    if (format->dxgi_format == DXGI_FORMAT_A8_UNORM)
+    {
+        if (allowed_swizzle)
+        {
+            components->r = VK_COMPONENT_SWIZZLE_ZERO;
+            components->g = VK_COMPONENT_SWIZZLE_ZERO;
+            components->b = VK_COMPONENT_SWIZZLE_ZERO;
+            components->a = VK_COMPONENT_SWIZZLE_R;
+        }
+        else
+        {
+            FIXME("Alpha swizzle is not supported.\n");
+        }
+    }
+
+    if (format->dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM
+            || format->dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
+    {
+        if (allowed_swizzle)
+        {
+            components->r = VK_COMPONENT_SWIZZLE_R;
+            components->g = VK_COMPONENT_SWIZZLE_G;
+            components->b = VK_COMPONENT_SWIZZLE_B;
+            components->a = VK_COMPONENT_SWIZZLE_ONE;
+        }
+        else
+        {
+            FIXME("B8G8R8X8 swizzle is not supported.\n");
+        }
+    }
+}
+
+static VkComponentSwizzle vk_component_swizzle_from_d3d12(unsigned int component_mapping,
+        unsigned int component_index)
+{
+    D3D12_SHADER_COMPONENT_MAPPING mapping
+            = D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(component_index, component_mapping);
+
+    switch (mapping)
+    {
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0:
+            return VK_COMPONENT_SWIZZLE_R;
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1:
+            return VK_COMPONENT_SWIZZLE_G;
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2:
+            return VK_COMPONENT_SWIZZLE_B;
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3:
+            return VK_COMPONENT_SWIZZLE_A;
+        case D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0:
+            return VK_COMPONENT_SWIZZLE_ZERO;
+        case D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1:
+            return VK_COMPONENT_SWIZZLE_ONE;
+    }
+
+    FIXME("Invalid component mapping %#x.\n", mapping);
+    return VK_COMPONENT_SWIZZLE_IDENTITY;
+}
+
+static void vk_component_mapping_from_d3d12(VkComponentMapping *components,
+        unsigned int component_mapping)
+{
+    components->r = vk_component_swizzle_from_d3d12(component_mapping, 0);
+    components->g = vk_component_swizzle_from_d3d12(component_mapping, 1);
+    components->b = vk_component_swizzle_from_d3d12(component_mapping, 2);
+    components->a = vk_component_swizzle_from_d3d12(component_mapping, 3);
+}
+
+static VkComponentSwizzle swizzle_vk_component(const VkComponentMapping *components,
+        VkComponentSwizzle component, VkComponentSwizzle swizzle)
+{
+    switch (swizzle)
+    {
+        case VK_COMPONENT_SWIZZLE_IDENTITY:
+            break;
+
+        case VK_COMPONENT_SWIZZLE_R:
+            component = components->r;
+            break;
+
+        case VK_COMPONENT_SWIZZLE_G:
+            component = components->g;
+            break;
+
+        case VK_COMPONENT_SWIZZLE_B:
+            component = components->b;
+            break;
+
+        case VK_COMPONENT_SWIZZLE_A:
+            component = components->a;
+            break;
+
+        case VK_COMPONENT_SWIZZLE_ONE:
+        case VK_COMPONENT_SWIZZLE_ZERO:
+            component = swizzle;
+            break;
+
+        default:
+            FIXME("Invalid component swizzle %#x.\n", swizzle);
+            break;
+    }
+
+    assert(component != VK_COMPONENT_SWIZZLE_IDENTITY);
+    return component;
+}
+
+static void vk_component_mapping_compose(VkComponentMapping *dst, const VkComponentMapping *b)
+{
+    const VkComponentMapping a = *dst;
+
+    dst->r = swizzle_vk_component(&a, a.r, b->r);
+    dst->g = swizzle_vk_component(&a, a.g, b->g);
+    dst->b = swizzle_vk_component(&a, a.b, b->b);
+    dst->a = swizzle_vk_component(&a, a.a, b->a);
+}
+
+static bool init_default_texture_view_desc(struct vkd3d_texture_view_desc *desc,
+        struct d3d12_resource *resource, DXGI_FORMAT view_format)
+{
+    const struct d3d12_device *device = resource->device;
+
+    if (!(desc->format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, view_format)))
+    {
+        FIXME("Failed to find format (resource format %#x, view format %#x).\n",
+                resource->desc.Format, view_format);
+        return false;
+    }
+
+    desc->miplevel_idx = 0;
+    desc->miplevel_count = 1;
+    desc->layer_idx = 0;
+    desc->layer_count = d3d12_resource_desc_get_layer_count(&resource->desc);
+
+    switch (resource->desc.Dimension)
+    {
+        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+            desc->view_type = resource->desc.DepthOrArraySize > 1
+                    ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
+            break;
+
+        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+            desc->view_type = resource->desc.DepthOrArraySize > 1
+                    ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
+            break;
+
+        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+            desc->view_type = VK_IMAGE_VIEW_TYPE_3D;
+            desc->layer_count = 1;
+            break;
+
+        default:
+            FIXME("Resource dimension %#x not implemented.\n", resource->desc.Dimension);
+            return false;
+    }
+
+    desc->components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    desc->components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+    desc->components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+    desc->components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+    desc->allowed_swizzle = false;
+    return true;
+}
+
+bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image,
+        const struct vkd3d_texture_view_desc *desc, struct vkd3d_view **view)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    const struct vkd3d_format *format = desc->format;
+    struct VkImageViewCreateInfo view_desc;
+    struct vkd3d_view *object;
+    VkImageView vk_view;
+    VkResult vr;
+
+    view_desc.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    view_desc.pNext = NULL;
+    view_desc.flags = 0;
+    view_desc.image = vk_image;
+    view_desc.viewType = desc->view_type;
+    view_desc.format = format->vk_format;
+    vkd3d_set_view_swizzle_for_format(&view_desc.components, format, desc->allowed_swizzle);
+    if (desc->allowed_swizzle)
+        vk_component_mapping_compose(&view_desc.components, &desc->components);
+    view_desc.subresourceRange.aspectMask = format->vk_aspect_mask;
+    view_desc.subresourceRange.baseMipLevel = desc->miplevel_idx;
+    view_desc.subresourceRange.levelCount = desc->miplevel_count;
+    view_desc.subresourceRange.baseArrayLayer = desc->layer_idx;
+    view_desc.subresourceRange.layerCount = desc->layer_count;
+    if ((vr = VK_CALL(vkCreateImageView(device->vk_device, &view_desc, NULL, &vk_view))) < 0)
+    {
+        WARN("Failed to create Vulkan image view, vr %d.\n", vr);
+        return false;
+    }
+
+    if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_IMAGE)))
+    {
+        VK_CALL(vkDestroyImageView(device->vk_device, vk_view, NULL));
+        return false;
+    }
+
+    object->u.vk_image_view = vk_view;
+    object->format = format;
+    object->info.texture.vk_view_type = desc->view_type;
+    object->info.texture.miplevel_idx = desc->miplevel_idx;
+    object->info.texture.layer_idx = desc->layer_idx;
+    object->info.texture.layer_count = desc->layer_count;
+    *view = object;
+    return true;
+}
+
+void d3d12_desc_create_cbv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc)
+{
+    struct VkDescriptorBufferInfo *buffer_info;
+    struct d3d12_resource *resource;
+
+    if (!desc)
+    {
+        WARN("Constant buffer desc is NULL.\n");
+        return;
+    }
+
+    if (desc->SizeInBytes & (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1))
+    {
+        WARN("Size is not %u bytes aligned.\n", D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
+        return;
+    }
+
+    buffer_info = &descriptor->u.vk_cbv_info;
+    if (desc->BufferLocation)
+    {
+        resource = vkd3d_gpu_va_allocator_dereference(&device->gpu_va_allocator, desc->BufferLocation);
+        buffer_info->buffer = resource->u.vk_buffer;
+        buffer_info->offset = desc->BufferLocation - resource->gpu_address;
+        buffer_info->range = min(desc->SizeInBytes, resource->desc.Width - buffer_info->offset);
+    }
+    else
+    {
+        /* NULL descriptor */
+        buffer_info->buffer = device->null_resources.vk_buffer;
+        buffer_info->offset = 0;
+        buffer_info->range = VKD3D_NULL_BUFFER_SIZE;
+    }
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_CBV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+}
+
+static unsigned int vkd3d_view_flags_from_d3d12_buffer_srv_flags(D3D12_BUFFER_SRV_FLAGS flags)
+{
+    if (flags == D3D12_BUFFER_SRV_FLAG_RAW)
+        return VKD3D_VIEW_RAW_BUFFER;
+    if (flags)
+        FIXME("Unhandled buffer SRV flags %#x.\n", flags);
+    return 0;
+}
+
+static void vkd3d_create_null_srv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, const D3D12_SHADER_RESOURCE_VIEW_DESC *desc)
+{
+    struct vkd3d_null_resources *null_resources = &device->null_resources;
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+    VkImage vk_image;
+
+    if (!desc)
+    {
+        WARN("D3D12_SHADER_RESOURCE_VIEW_DESC is required for NULL view.\n");
+        return;
+    }
+
+    switch (desc->ViewDimension)
+    {
+        case D3D12_SRV_DIMENSION_BUFFER:
+            WARN("Creating NULL buffer SRV %#x.\n", desc->Format);
+
+            if (vkd3d_create_buffer_view(device, null_resources->vk_buffer,
+                    vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false),
+                    0, VKD3D_NULL_BUFFER_SIZE, &view))
+            {
+                descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_SRV;
+                descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+                descriptor->u.view = view;
+            }
+            return;
+
+        case D3D12_SRV_DIMENSION_TEXTURE2D:
+            vk_image = null_resources->vk_2d_image;
+            vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+            break;
+        case D3D12_SRV_DIMENSION_TEXTURE2DARRAY:
+            vk_image = null_resources->vk_2d_image;
+            vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+            break;
+
+        default:
+            FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+            return;
+    }
+
+    WARN("Creating NULL SRV %#x.\n", desc->ViewDimension);
+
+    vkd3d_desc.format = vkd3d_get_format(device, VKD3D_NULL_VIEW_FORMAT, false);
+    vkd3d_desc.miplevel_idx = 0;
+    vkd3d_desc.miplevel_count = 1;
+    vkd3d_desc.layer_idx = 0;
+    vkd3d_desc.layer_count = 1;
+    vkd3d_desc.components.r = VK_COMPONENT_SWIZZLE_ZERO;
+    vkd3d_desc.components.g = VK_COMPONENT_SWIZZLE_ZERO;
+    vkd3d_desc.components.b = VK_COMPONENT_SWIZZLE_ZERO;
+    vkd3d_desc.components.a = VK_COMPONENT_SWIZZLE_ZERO;
+    vkd3d_desc.allowed_swizzle = true;
+
+    if (!vkd3d_create_texture_view(device, vk_image, &vkd3d_desc, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_SRV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+    descriptor->u.view = view;
+}
+
+static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, struct d3d12_resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc)
+{
+    struct vkd3d_view *view;
+    unsigned int flags;
+
+    if (!desc)
+    {
+        FIXME("Default SRV views not supported.\n");
+        return;
+    }
+
+    if (desc->ViewDimension != D3D12_SRV_DIMENSION_BUFFER)
+    {
+        WARN("Unexpected view dimension %#x.\n", desc->ViewDimension);
+        return;
+    }
+
+    flags = vkd3d_view_flags_from_d3d12_buffer_srv_flags(desc->u.Buffer.Flags);
+    if (!vkd3d_create_buffer_view_for_resource(device, resource, desc->Format,
+            desc->u.Buffer.FirstElement, desc->u.Buffer.NumElements,
+            desc->u.Buffer.StructureByteStride, flags, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_SRV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+    descriptor->u.view = view;
+}
+
+void d3d12_desc_create_srv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, struct d3d12_resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc)
+{
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+
+    if (!resource)
+    {
+        vkd3d_create_null_srv(descriptor, device, desc);
+        return;
+    }
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        vkd3d_create_buffer_srv(descriptor, device, resource, desc);
+        return;
+    }
+
+    if (!init_default_texture_view_desc(&vkd3d_desc, resource, desc ? desc->Format : 0))
+        return;
+
+    vkd3d_desc.miplevel_count = VK_REMAINING_MIP_LEVELS;
+    vkd3d_desc.allowed_swizzle = true;
+
+    if (desc)
+    {
+        if (desc->Shader4ComponentMapping != D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING)
+        {
+            TRACE("Component mapping %s for format %#x.\n",
+                    debug_d3d12_shader_component_mapping(desc->Shader4ComponentMapping), desc->Format);
+
+            vk_component_mapping_from_d3d12(&vkd3d_desc.components, desc->Shader4ComponentMapping);
+        }
+
+        switch (desc->ViewDimension)
+        {
+            case D3D12_SRV_DIMENSION_TEXTURE2D:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+                vkd3d_desc.miplevel_idx = desc->u.Texture2D.MostDetailedMip;
+                vkd3d_desc.miplevel_count = desc->u.Texture2D.MipLevels;
+                if (desc->u.Texture2D.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2D.PlaneSlice);
+                if (desc->u.Texture2D.ResourceMinLODClamp)
+                    FIXME("Unhandled min LOD clamp %.8e.\n", desc->u.Texture2D.ResourceMinLODClamp);
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURE2DARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.Texture2DArray.MostDetailedMip;
+                vkd3d_desc.miplevel_count = desc->u.Texture2DArray.MipLevels;
+                vkd3d_desc.layer_idx = desc->u.Texture2DArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DArray.ArraySize;
+                if (desc->u.Texture2DArray.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2DArray.PlaneSlice);
+                if (desc->u.Texture2DArray.ResourceMinLODClamp)
+                    FIXME("Unhandled min LOD clamp %.8e.\n", desc->u.Texture2DArray.ResourceMinLODClamp);
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURE2DMS:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.layer_idx = desc->u.Texture2DMSArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DMSArray.ArraySize;
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURE3D:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_3D;
+                vkd3d_desc.miplevel_idx = desc->u.Texture3D.MostDetailedMip;
+                vkd3d_desc.miplevel_count = desc->u.Texture3D.MipLevels;
+                if (desc->u.Texture3D.ResourceMinLODClamp)
+                    FIXME("Unhandled min LOD clamp %.8e.\n", desc->u.Texture2D.ResourceMinLODClamp);
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURECUBE:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_CUBE;
+                vkd3d_desc.miplevel_idx = desc->u.TextureCube.MostDetailedMip;
+                vkd3d_desc.miplevel_count = desc->u.TextureCube.MipLevels;
+                vkd3d_desc.layer_count = 6;
+                if (desc->u.TextureCube.ResourceMinLODClamp)
+                    FIXME("Unhandled min LOD clamp %.8e.\n", desc->u.TextureCube.ResourceMinLODClamp);
+                break;
+            case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.TextureCubeArray.MostDetailedMip;
+                vkd3d_desc.miplevel_count = desc->u.TextureCubeArray.MipLevels;
+                vkd3d_desc.layer_idx = desc->u.TextureCubeArray.First2DArrayFace;
+                vkd3d_desc.layer_count = desc->u.TextureCubeArray.NumCubes;
+                if (vkd3d_desc.layer_count != VK_REMAINING_ARRAY_LAYERS)
+                    vkd3d_desc.layer_count *= 6;
+                if (desc->u.TextureCubeArray.ResourceMinLODClamp)
+                    FIXME("Unhandled min LOD clamp %.8e.\n", desc->u.TextureCubeArray.ResourceMinLODClamp);
+                break;
+            default:
+                FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+        }
+    }
+
+    if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_SRV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+    descriptor->u.view = view;
+}
+
+static unsigned int vkd3d_view_flags_from_d3d12_buffer_uav_flags(D3D12_BUFFER_UAV_FLAGS flags)
+{
+    if (flags == D3D12_BUFFER_UAV_FLAG_RAW)
+        return VKD3D_VIEW_RAW_BUFFER;
+    if (flags)
+        FIXME("Unhandled buffer UAV flags %#x.\n", flags);
+    return 0;
+}
+
+static void vkd3d_create_null_uav(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc)
+{
+    struct vkd3d_null_resources *null_resources = &device->null_resources;
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+    VkImage vk_image;
+
+    if (!desc)
+    {
+        WARN("View desc is required for NULL view.\n");
+        return;
+    }
+
+    switch (desc->ViewDimension)
+    {
+        case D3D12_UAV_DIMENSION_BUFFER:
+            WARN("Creating NULL buffer UAV %#x.\n", desc->Format);
+
+            if (vkd3d_create_buffer_view(device, null_resources->vk_storage_buffer,
+                    vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false),
+                    0, VKD3D_NULL_BUFFER_SIZE, &view))
+            {
+                descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_UAV;
+                descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+                descriptor->u.view = view;
+            }
+            return;
+
+        case D3D12_UAV_DIMENSION_TEXTURE2D:
+            vk_image = null_resources->vk_2d_storage_image;
+            vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+            break;
+        case D3D12_UAV_DIMENSION_TEXTURE2DARRAY:
+            vk_image = null_resources->vk_2d_storage_image;
+            vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+            break;
+
+        default:
+            FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+            return;
+    }
+
+    WARN("Creating NULL UAV %#x.\n", desc->ViewDimension);
+
+    vkd3d_desc.format = vkd3d_get_format(device, VKD3D_NULL_VIEW_FORMAT, false);
+    vkd3d_desc.miplevel_idx = 0;
+    vkd3d_desc.miplevel_count = 1;
+    vkd3d_desc.layer_idx = 0;
+    vkd3d_desc.layer_count = 1;
+    vkd3d_desc.components.r = VK_COMPONENT_SWIZZLE_R;
+    vkd3d_desc.components.g = VK_COMPONENT_SWIZZLE_G;
+    vkd3d_desc.components.b = VK_COMPONENT_SWIZZLE_B;
+    vkd3d_desc.components.a = VK_COMPONENT_SWIZZLE_A;
+    vkd3d_desc.allowed_swizzle = false;
+
+    if (!vkd3d_create_texture_view(device, vk_image, &vkd3d_desc, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_UAV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+    descriptor->u.view = view;
+}
+
+static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_device *device,
+        struct d3d12_resource *resource, struct d3d12_resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc)
+{
+    struct vkd3d_view *view;
+    unsigned int flags;
+
+    if (!desc)
+    {
+        FIXME("Default UAV views not supported.\n");
+        return;
+    }
+
+    if (desc->ViewDimension != D3D12_UAV_DIMENSION_BUFFER)
+    {
+        WARN("Unexpected view dimension %#x.\n", desc->ViewDimension);
+        return;
+    }
+
+    if (desc->u.Buffer.CounterOffsetInBytes)
+        FIXME("Ignoring counter offset %"PRIu64".\n", desc->u.Buffer.CounterOffsetInBytes);
+
+    flags = vkd3d_view_flags_from_d3d12_buffer_uav_flags(desc->u.Buffer.Flags);
+    if (!vkd3d_create_buffer_view_for_resource(device, resource, desc->Format,
+            desc->u.Buffer.FirstElement, desc->u.Buffer.NumElements,
+            desc->u.Buffer.StructureByteStride, flags, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_UAV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+    descriptor->u.view = view;
+
+    if (counter_resource)
+    {
+        const struct vkd3d_format *format;
+
+        assert(d3d12_resource_is_buffer(counter_resource));
+        assert(desc->u.Buffer.StructureByteStride);
+
+        format = vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+        if (!vkd3d_create_vk_buffer_view(device, counter_resource->u.vk_buffer, format,
+                desc->u.Buffer.CounterOffsetInBytes, sizeof(uint32_t), &view->vk_counter_view))
+        {
+            WARN("Failed to create counter buffer view.\n");
+            view->vk_counter_view = VK_NULL_HANDLE;
+            d3d12_desc_destroy(descriptor, device);
+        }
+    }
+}
+
+static void vkd3d_create_texture_uav(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, struct d3d12_resource *resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc)
+{
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+
+    if (!init_default_texture_view_desc(&vkd3d_desc, resource, desc ? desc->Format : 0))
+        return;
+
+    if (vkd3d_format_is_compressed(vkd3d_desc.format))
+    {
+        WARN("UAVs cannot be created for compressed formats.\n");
+        return;
+    }
+
+    if (desc)
+    {
+        switch (desc->ViewDimension)
+        {
+            case D3D12_UAV_DIMENSION_TEXTURE2D:
+                vkd3d_desc.miplevel_idx = desc->u.Texture2D.MipSlice;
+                if (desc->u.Texture2D.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2D.PlaneSlice);
+                break;
+            case D3D12_UAV_DIMENSION_TEXTURE2DARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.Texture2DArray.MipSlice;
+                vkd3d_desc.layer_idx = desc->u.Texture2DArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DArray.ArraySize;
+                if (desc->u.Texture2DArray.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2DArray.PlaneSlice);
+                break;
+            case D3D12_UAV_DIMENSION_TEXTURE3D:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_3D;
+                vkd3d_desc.miplevel_idx = desc->u.Texture3D.MipSlice;
+                if (desc->u.Texture3D.FirstWSlice || desc->u.Texture3D.WSize != resource->desc.DepthOrArraySize)
+                    FIXME("Unhandled depth view %u-%u.\n",
+                            desc->u.Texture3D.FirstWSlice, desc->u.Texture3D.WSize);
+                break;
+            default:
+                FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+        }
+    }
+
+    if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view))
+        return;
+
+    descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_UAV;
+    descriptor->vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+    descriptor->u.view = view;
+}
+
+void d3d12_desc_create_uav(struct d3d12_desc *descriptor, struct d3d12_device *device,
+        struct d3d12_resource *resource, struct d3d12_resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc)
+{
+    if (!resource)
+    {
+        if (counter_resource)
+            FIXME("Ignoring counter resource %p.\n", counter_resource);
+        vkd3d_create_null_uav(descriptor, device, desc);
+        return;
+    }
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        vkd3d_create_buffer_uav(descriptor, device, resource, counter_resource, desc);
+    }
+    else
+    {
+        if (counter_resource)
+            FIXME("Unexpected counter resource for texture view.\n");
+        vkd3d_create_texture_uav(descriptor, device, resource, desc);
+    }
+}
+
+bool vkd3d_create_raw_buffer_view(struct d3d12_device *device,
+        D3D12_GPU_VIRTUAL_ADDRESS gpu_address, VkBufferView *vk_buffer_view)
+{
+    const struct vkd3d_format *format;
+    struct d3d12_resource *resource;
+
+    format = vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+    resource = vkd3d_gpu_va_allocator_dereference(&device->gpu_va_allocator, gpu_address);
+    assert(d3d12_resource_is_buffer(resource));
+    return vkd3d_create_vk_buffer_view(device, resource->u.vk_buffer, format,
+            gpu_address - resource->gpu_address, VK_WHOLE_SIZE, vk_buffer_view);
+}
+
+/* samplers */
+static VkFilter vk_filter_from_d3d12(D3D12_FILTER_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_FILTER_TYPE_POINT:
+            return VK_FILTER_NEAREST;
+        case D3D12_FILTER_TYPE_LINEAR:
+            return VK_FILTER_LINEAR;
+        default:
+            FIXME("Unhandled filter type %#x.\n", type);
+            return VK_FILTER_NEAREST;
+    }
+}
+
+static VkSamplerMipmapMode vk_mipmap_mode_from_d3d12(D3D12_FILTER_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_FILTER_TYPE_POINT:
+            return VK_SAMPLER_MIPMAP_MODE_NEAREST;
+        case D3D12_FILTER_TYPE_LINEAR:
+            return VK_SAMPLER_MIPMAP_MODE_LINEAR;
+        default:
+            FIXME("Unhandled filter type %#x.\n", type);
+            return VK_SAMPLER_MIPMAP_MODE_NEAREST;
+    }
+}
+
+static VkSamplerAddressMode vk_address_mode_from_d3d12(D3D12_TEXTURE_ADDRESS_MODE mode)
+{
+    switch (mode)
+    {
+        case D3D12_TEXTURE_ADDRESS_MODE_WRAP:
+            return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+        case D3D12_TEXTURE_ADDRESS_MODE_MIRROR:
+            return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
+        case D3D12_TEXTURE_ADDRESS_MODE_CLAMP:
+            return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+        case D3D12_TEXTURE_ADDRESS_MODE_BORDER:
+            return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+            /* D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE requires VK_KHR_mirror_clamp_to_edge. */
+        default:
+            FIXME("Unhandled address mode %#x.\n", mode);
+            return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    }
+}
+
+static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER filter,
+        D3D12_TEXTURE_ADDRESS_MODE address_u, D3D12_TEXTURE_ADDRESS_MODE address_v,
+        D3D12_TEXTURE_ADDRESS_MODE address_w, float mip_lod_bias, unsigned int max_anisotropy,
+        D3D12_COMPARISON_FUNC comparison_func, float min_lod, float max_lod,
+        VkSampler *vk_sampler)
+{
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct VkSamplerCreateInfo sampler_desc;
+    VkResult vr;
+
+    vk_procs = &device->vk_procs;
+
+    if (D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MINIMUM
+            || D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MAXIMUM)
+        FIXME("Min/max reduction mode not supported.\n");
+
+    sampler_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+    sampler_desc.pNext = NULL;
+    sampler_desc.flags = 0;
+    sampler_desc.magFilter = vk_filter_from_d3d12(D3D12_DECODE_MAG_FILTER(filter));
+    sampler_desc.minFilter = vk_filter_from_d3d12(D3D12_DECODE_MIN_FILTER(filter));
+    sampler_desc.mipmapMode = vk_mipmap_mode_from_d3d12(D3D12_DECODE_MIP_FILTER(filter));
+    sampler_desc.addressModeU = vk_address_mode_from_d3d12(address_u);
+    sampler_desc.addressModeV = vk_address_mode_from_d3d12(address_v);
+    sampler_desc.addressModeW = vk_address_mode_from_d3d12(address_w);
+    sampler_desc.mipLodBias = mip_lod_bias;
+    sampler_desc.anisotropyEnable = D3D12_DECODE_IS_ANISOTROPIC_FILTER(filter);
+    sampler_desc.maxAnisotropy = max_anisotropy;
+    sampler_desc.compareEnable = D3D12_DECODE_IS_COMPARISON_FILTER(filter);
+    sampler_desc.compareOp = sampler_desc.compareEnable ? vk_compare_op_from_d3d12(comparison_func) : 0;
+    sampler_desc.minLod = min_lod;
+    sampler_desc.maxLod = max_lod;
+    sampler_desc.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+    sampler_desc.unnormalizedCoordinates = VK_FALSE;
+    if ((vr = VK_CALL(vkCreateSampler(device->vk_device, &sampler_desc, NULL, vk_sampler))) < 0)
+        WARN("Failed to create Vulkan sampler, vr %d.\n", vr);
+
+    return vr;
+}
+
+void d3d12_desc_create_sampler(struct d3d12_desc *sampler,
+        struct d3d12_device *device, const D3D12_SAMPLER_DESC *desc)
+{
+    struct vkd3d_view *view;
+
+    if (!desc)
+    {
+        WARN("NULL sampler desc.\n");
+        return;
+    }
+
+    if (desc->AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER
+            || desc->AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER
+            || desc->AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
+        FIXME("Ignoring border color {%.8e, %.8e, %.8e, %.8e}.\n",
+                desc->BorderColor[0], desc->BorderColor[1], desc->BorderColor[2], desc->BorderColor[3]);
+
+    if (!(view = vkd3d_view_create(VKD3D_VIEW_TYPE_SAMPLER)))
+        return;
+
+    if (d3d12_create_sampler(device, desc->Filter, desc->AddressU,
+            desc->AddressV, desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy,
+            desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, &view->u.vk_sampler) < 0)
+    {
+        vkd3d_free(view);
+        return;
+    }
+
+    sampler->magic = VKD3D_DESCRIPTOR_MAGIC_SAMPLER;
+    sampler->vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLER;
+    sampler->u.view = view;
+}
+
+HRESULT vkd3d_create_static_sampler(struct d3d12_device *device,
+        const D3D12_STATIC_SAMPLER_DESC *desc, VkSampler *vk_sampler)
+{
+    VkResult vr;
+
+    if (desc->AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER
+            || desc->AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER
+            || desc->AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
+        FIXME("Ignoring border %#x.\n", desc->BorderColor);
+
+    vr = d3d12_create_sampler(device, desc->Filter, desc->AddressU,
+            desc->AddressV, desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy,
+            desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, vk_sampler);
+    return hresult_from_vk_result(vr);
+}
+
+/* RTVs */
+static void d3d12_rtv_desc_destroy(struct d3d12_rtv_desc *rtv, struct d3d12_device *device)
+{
+    if (rtv->magic != VKD3D_DESCRIPTOR_MAGIC_RTV)
+        return;
+
+    vkd3d_view_decref(rtv->view, device);
+    memset(rtv, 0, sizeof(*rtv));
+}
+
+void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_device *device,
+        struct d3d12_resource *resource, const D3D12_RENDER_TARGET_VIEW_DESC *desc)
+{
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+
+    d3d12_rtv_desc_destroy(rtv_desc, device);
+
+    if (!resource)
+    {
+        FIXME("NULL resource RTV not implemented.\n");
+        return;
+    }
+
+    if (!init_default_texture_view_desc(&vkd3d_desc, resource, desc ? desc->Format : 0))
+        return;
+
+    if (vkd3d_desc.format->vk_aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT)
+    {
+        WARN("Trying to create RTV for depth/stencil format %#x.\n", vkd3d_desc.format->dxgi_format);
+        return;
+    }
+
+    if (desc)
+    {
+        switch (desc->ViewDimension)
+        {
+            case D3D12_RTV_DIMENSION_TEXTURE2D:
+                vkd3d_desc.miplevel_idx = desc->u.Texture2D.MipSlice;
+                if (desc->u.Texture2D.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2D.PlaneSlice);
+                break;
+            case D3D12_RTV_DIMENSION_TEXTURE2DARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.Texture2DArray.MipSlice;
+                vkd3d_desc.layer_idx = desc->u.Texture2DArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DArray.ArraySize;
+                if (desc->u.Texture2DArray.PlaneSlice)
+                    FIXME("Ignoring plane slice %u.\n", desc->u.Texture2DArray.PlaneSlice);
+                break;
+            case D3D12_RTV_DIMENSION_TEXTURE2DMS:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+                break;
+            case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.layer_idx = desc->u.Texture2DMSArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DMSArray.ArraySize;
+                break;
+            case D3D12_RTV_DIMENSION_TEXTURE3D:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.Texture3D.MipSlice;
+                vkd3d_desc.layer_idx = desc->u.Texture3D.FirstWSlice;
+                vkd3d_desc.layer_count = desc->u.Texture3D.WSize;
+                break;
+            default:
+                FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+        }
+    }
+    else if (resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
+    {
+        vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+        vkd3d_desc.layer_idx = 0;
+        vkd3d_desc.layer_count = resource->desc.DepthOrArraySize;
+    }
+
+    assert(d3d12_resource_is_texture(resource));
+
+    if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view))
+        return;
+
+    rtv_desc->magic = VKD3D_DESCRIPTOR_MAGIC_RTV;
+    rtv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc);
+    rtv_desc->format = vkd3d_desc.format;
+    rtv_desc->width = d3d12_resource_desc_get_width(&resource->desc, vkd3d_desc.miplevel_idx);
+    rtv_desc->height = d3d12_resource_desc_get_height(&resource->desc, vkd3d_desc.miplevel_idx);
+    rtv_desc->layer_count = vkd3d_desc.layer_count;
+    rtv_desc->view = view;
+    rtv_desc->resource = resource;
+}
+
+/* DSVs */
+static void d3d12_dsv_desc_destroy(struct d3d12_dsv_desc *dsv, struct d3d12_device *device)
+{
+    if (dsv->magic != VKD3D_DESCRIPTOR_MAGIC_DSV)
+        return;
+
+    vkd3d_view_decref(dsv->view, device);
+    memset(dsv, 0, sizeof(*dsv));
+}
+
+void d3d12_dsv_desc_create_dsv(struct d3d12_dsv_desc *dsv_desc, struct d3d12_device *device,
+        struct d3d12_resource *resource, const D3D12_DEPTH_STENCIL_VIEW_DESC *desc)
+{
+    struct vkd3d_texture_view_desc vkd3d_desc;
+    struct vkd3d_view *view;
+
+    d3d12_dsv_desc_destroy(dsv_desc, device);
+
+    if (!resource)
+    {
+        FIXME("NULL resource DSV not implemented.\n");
+        return;
+    }
+
+    if (resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
+    {
+        WARN("Cannot create DSV for 3D texture.\n");
+        return;
+    }
+
+    if (!init_default_texture_view_desc(&vkd3d_desc, resource, desc ? desc->Format : 0))
+        return;
+
+    if (!(vkd3d_desc.format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))
+    {
+        WARN("Trying to create DSV for format %#x.\n", vkd3d_desc.format->dxgi_format);
+        return;
+    }
+
+    if (desc)
+    {
+        if (desc->Flags)
+            FIXME("Ignoring flags %#x.\n", desc->Flags);
+
+        switch (desc->ViewDimension)
+        {
+            case D3D12_DSV_DIMENSION_TEXTURE2D:
+                vkd3d_desc.miplevel_idx = desc->u.Texture2D.MipSlice;
+                break;
+            case D3D12_DSV_DIMENSION_TEXTURE2DARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.miplevel_idx = desc->u.Texture2DArray.MipSlice;
+                vkd3d_desc.layer_idx = desc->u.Texture2DArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DArray.ArraySize;
+                break;
+            case D3D12_DSV_DIMENSION_TEXTURE2DMS:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D;
+                break;
+            case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY:
+                vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+                vkd3d_desc.layer_idx = desc->u.Texture2DMSArray.FirstArraySlice;
+                vkd3d_desc.layer_count = desc->u.Texture2DMSArray.ArraySize;
+                break;
+            default:
+                FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension);
+        }
+    }
+
+    assert(d3d12_resource_is_texture(resource));
+
+    if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view))
+        return;
+
+    dsv_desc->magic = VKD3D_DESCRIPTOR_MAGIC_DSV;
+    dsv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc);
+    dsv_desc->format = vkd3d_desc.format;
+    dsv_desc->width = d3d12_resource_desc_get_width(&resource->desc, vkd3d_desc.miplevel_idx);
+    dsv_desc->height = d3d12_resource_desc_get_height(&resource->desc, vkd3d_desc.miplevel_idx);
+    dsv_desc->layer_count = vkd3d_desc.layer_count;
+    dsv_desc->view = view;
+    dsv_desc->resource = resource;
+}
+
+/* ID3D12DescriptorHeap */
+static inline struct d3d12_descriptor_heap *impl_from_ID3D12DescriptorHeap(ID3D12DescriptorHeap *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_descriptor_heap, ID3D12DescriptorHeap_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_QueryInterface(ID3D12DescriptorHeap *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12DescriptorHeap)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12DescriptorHeap_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_AddRef(ID3D12DescriptorHeap *iface)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+    ULONG refcount = InterlockedIncrement(&heap->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", heap, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHeap *iface)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+    ULONG refcount = InterlockedDecrement(&heap->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", heap, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = heap->device;
+        unsigned int i;
+
+        vkd3d_private_store_destroy(&heap->private_store);
+
+        switch (heap->desc.Type)
+        {
+            case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV:
+            case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER:
+            {
+                struct d3d12_desc *descriptors = (struct d3d12_desc *)heap->descriptors;
+
+                for (i = 0; i < heap->desc.NumDescriptors; ++i)
+                {
+                    d3d12_desc_destroy(&descriptors[i], device);
+                }
+                break;
+            }
+
+            case D3D12_DESCRIPTOR_HEAP_TYPE_RTV:
+            {
+                struct d3d12_rtv_desc *rtvs = (struct d3d12_rtv_desc *)heap->descriptors;
+
+                for (i = 0; i < heap->desc.NumDescriptors; ++i)
+                {
+                    d3d12_rtv_desc_destroy(&rtvs[i], device);
+                }
+                break;
+            }
+
+            case D3D12_DESCRIPTOR_HEAP_TYPE_DSV:
+            {
+                struct d3d12_dsv_desc *dsvs = (struct d3d12_dsv_desc *)heap->descriptors;
+
+                for (i = 0; i < heap->desc.NumDescriptors; ++i)
+                {
+                    d3d12_dsv_desc_destroy(&dsvs[i], device);
+                }
+                break;
+            }
+
+            default:
+                break;
+        }
+
+        vkd3d_free(heap);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_GetPrivateData(ID3D12DescriptorHeap *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_SetPrivateData(ID3D12DescriptorHeap *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_SetPrivateDataInterface(ID3D12DescriptorHeap *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&heap->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_SetName(ID3D12DescriptorHeap *iface, const WCHAR *name)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, heap->device->wchar_size));
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_GetDevice(ID3D12DescriptorHeap *iface, REFIID iid, void **device)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(heap->device, iid, device);
+}
+
+static D3D12_DESCRIPTOR_HEAP_DESC * STDMETHODCALLTYPE d3d12_descriptor_heap_GetDesc(ID3D12DescriptorHeap *iface,
+        D3D12_DESCRIPTOR_HEAP_DESC *desc)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, desc %p.\n", iface, desc);
+
+    *desc = heap->desc;
+    return desc;
+}
+
+static D3D12_CPU_DESCRIPTOR_HANDLE * STDMETHODCALLTYPE d3d12_descriptor_heap_GetCPUDescriptorHandleForHeapStart(
+        ID3D12DescriptorHeap *iface, D3D12_CPU_DESCRIPTOR_HANDLE *descriptor)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, descriptor %p.\n", iface, descriptor);
+
+    descriptor->ptr = (SIZE_T)heap->descriptors;
+
+    return descriptor;
+}
+
+static D3D12_GPU_DESCRIPTOR_HANDLE * STDMETHODCALLTYPE d3d12_descriptor_heap_GetGPUDescriptorHandleForHeapStart(
+        ID3D12DescriptorHeap *iface, D3D12_GPU_DESCRIPTOR_HANDLE *descriptor)
+{
+    struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
+
+    TRACE("iface %p, descriptor %p.\n", iface, descriptor);
+
+    descriptor->ptr = (uint64_t)(intptr_t)heap->descriptors;
+
+    return descriptor;
+}
+
+static const struct ID3D12DescriptorHeapVtbl d3d12_descriptor_heap_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_descriptor_heap_QueryInterface,
+    d3d12_descriptor_heap_AddRef,
+    d3d12_descriptor_heap_Release,
+    /* ID3D12Object methods */
+    d3d12_descriptor_heap_GetPrivateData,
+    d3d12_descriptor_heap_SetPrivateData,
+    d3d12_descriptor_heap_SetPrivateDataInterface,
+    d3d12_descriptor_heap_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_descriptor_heap_GetDevice,
+    /* ID3D12DescriptorHeap methods */
+    d3d12_descriptor_heap_GetDesc,
+    d3d12_descriptor_heap_GetCPUDescriptorHandleForHeapStart,
+    d3d12_descriptor_heap_GetGPUDescriptorHandleForHeapStart,
+};
+
+static HRESULT d3d12_descriptor_heap_init(struct d3d12_descriptor_heap *descriptor_heap,
+        struct d3d12_device *device, const D3D12_DESCRIPTOR_HEAP_DESC *desc)
+{
+    HRESULT hr;
+
+    descriptor_heap->ID3D12DescriptorHeap_iface.lpVtbl = &d3d12_descriptor_heap_vtbl;
+    descriptor_heap->refcount = 1;
+
+    descriptor_heap->desc = *desc;
+
+    if (FAILED(hr = vkd3d_private_store_init(&descriptor_heap->private_store)))
+        return hr;
+
+    d3d12_device_add_ref(descriptor_heap->device = device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc, struct d3d12_descriptor_heap **descriptor_heap)
+{
+    size_t max_descriptor_count, descriptor_size;
+    struct d3d12_descriptor_heap *object;
+    HRESULT hr;
+
+    if (!(descriptor_size = d3d12_device_get_descriptor_handle_increment_size(device, desc->Type)))
+    {
+        WARN("No descriptor size for descriptor type %#x.\n", desc->Type);
+        return E_INVALIDARG;
+    }
+
+    if ((desc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
+            && (desc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV || desc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_DSV))
+    {
+        WARN("RTV/DSV descriptor heaps cannot be shader visible.\n");
+        return E_INVALIDARG;
+    }
+
+    max_descriptor_count = (~(size_t)0 - sizeof(*object)) / descriptor_size;
+    if (desc->NumDescriptors > max_descriptor_count)
+    {
+        WARN("Invalid descriptor count %u (max %zu).\n", desc->NumDescriptors, max_descriptor_count);
+        return E_OUTOFMEMORY;
+    }
+
+    if (!(object = vkd3d_malloc(offsetof(struct d3d12_descriptor_heap,
+            descriptors[descriptor_size * desc->NumDescriptors]))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_descriptor_heap_init(object, device, desc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    memset(object->descriptors, 0, descriptor_size * desc->NumDescriptors);
+
+    TRACE("Created descriptor heap %p.\n", object);
+
+    *descriptor_heap = object;
+
+    return S_OK;
+}
+
+/* ID3D12QueryHeap */
+static inline struct d3d12_query_heap *impl_from_ID3D12QueryHeap(ID3D12QueryHeap *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_query_heap, ID3D12QueryHeap_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_QueryInterface(ID3D12QueryHeap *iface,
+        REFIID iid, void **out)
+{
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_ID3D12QueryHeap)
+            || IsEqualGUID(iid, &IID_ID3D12Pageable)
+            || IsEqualGUID(iid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(iid, &IID_ID3D12Object)
+            || IsEqualGUID(iid, &IID_IUnknown))
+    {
+        ID3D12QueryHeap_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_query_heap_AddRef(ID3D12QueryHeap *iface)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+    ULONG refcount = InterlockedIncrement(&heap->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", heap, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_query_heap_Release(ID3D12QueryHeap *iface)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+    ULONG refcount = InterlockedDecrement(&heap->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", heap, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = heap->device;
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        vkd3d_private_store_destroy(&heap->private_store);
+
+        VK_CALL(vkDestroyQueryPool(device->vk_device, heap->vk_query_pool, NULL));
+
+        vkd3d_free(heap);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_GetPrivateData(ID3D12QueryHeap *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_SetPrivateData(ID3D12QueryHeap *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&heap->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_SetPrivateDataInterface(ID3D12QueryHeap *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&heap->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_SetName(ID3D12QueryHeap *iface, const WCHAR *name)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, heap->device->wchar_size));
+
+    return vkd3d_set_vk_object_name(heap->device, (uint64_t)heap->vk_query_pool,
+            VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, name);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_query_heap_GetDevice(ID3D12QueryHeap *iface, REFIID iid, void **device)
+{
+    struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(heap->device, iid, device);
+}
+
+static const struct ID3D12QueryHeapVtbl d3d12_query_heap_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_query_heap_QueryInterface,
+    d3d12_query_heap_AddRef,
+    d3d12_query_heap_Release,
+    /* ID3D12Object methods */
+    d3d12_query_heap_GetPrivateData,
+    d3d12_query_heap_SetPrivateData,
+    d3d12_query_heap_SetPrivateDataInterface,
+    d3d12_query_heap_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_query_heap_GetDevice,
+};
+
+struct d3d12_query_heap *unsafe_impl_from_ID3D12QueryHeap(ID3D12QueryHeap *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_query_heap_vtbl);
+    return impl_from_ID3D12QueryHeap(iface);
+}
+
+HRESULT d3d12_query_heap_create(struct d3d12_device *device, const D3D12_QUERY_HEAP_DESC *desc,
+        struct d3d12_query_heap **heap)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct d3d12_query_heap *object;
+    VkQueryPoolCreateInfo pool_info;
+    unsigned int element_count;
+    VkResult vr;
+    HRESULT hr;
+
+    element_count = DIV_ROUND_UP(desc->Count, sizeof(*object->availability_mask) * CHAR_BIT);
+    if (!(object = vkd3d_malloc(offsetof(struct d3d12_query_heap, availability_mask[element_count]))))
+        return E_OUTOFMEMORY;
+
+    object->ID3D12QueryHeap_iface.lpVtbl = &d3d12_query_heap_vtbl;
+    object->refcount = 1;
+    object->device = device;
+    memset(object->availability_mask, 0, element_count * sizeof(*object->availability_mask));
+
+    pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+    pool_info.pNext = NULL;
+    pool_info.flags = 0;
+    pool_info.queryCount = desc->Count;
+
+    switch (desc->Type)
+    {
+        case D3D12_QUERY_HEAP_TYPE_OCCLUSION:
+            pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
+            pool_info.pipelineStatistics = 0;
+            break;
+
+        case D3D12_QUERY_HEAP_TYPE_TIMESTAMP:
+            pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
+            pool_info.pipelineStatistics = 0;
+            break;
+
+        case D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS:
+            pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
+            pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
+                    | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
+            break;
+
+        case D3D12_QUERY_HEAP_TYPE_SO_STATISTICS:
+            if (!device->vk_info.transform_feedback_queries)
+            {
+                FIXME("Transform feedback queries are not supported by Vulkan implementation.\n");
+                vkd3d_free(object);
+                return E_NOTIMPL;
+            }
+
+            pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
+            pool_info.pipelineStatistics = 0;
+            break;
+
+        default:
+            WARN("Invalid query heap type %u.\n", desc->Type);
+            vkd3d_free(object);
+            return E_INVALIDARG;
+    }
+
+    if (FAILED(hr = vkd3d_private_store_init(&object->private_store)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    if ((vr = VK_CALL(vkCreateQueryPool(device->vk_device, &pool_info, NULL, &object->vk_query_pool))) < 0)
+    {
+        WARN("Failed to create Vulkan query pool, vr %d.\n", vr);
+        vkd3d_private_store_destroy(&object->private_store);
+        vkd3d_free(object);
+        return hresult_from_vk_result(vr);
+    }
+
+    d3d12_device_add_ref(device);
+
+    TRACE("Created query heap %p.\n", object);
+
+    *heap = object;
+
+    return S_OK;
+}
+
+static HRESULT vkd3d_init_null_resources_data(struct vkd3d_null_resources *null_resource,
+        struct d3d12_device *device)
+{
+    const bool use_sparse_resources = device->vk_info.sparse_properties.residencyNonResidentStrict;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    static const VkClearColorValue clear_color = {{0}};
+    VkCommandBufferAllocateInfo command_buffer_info;
+    VkCommandPool vk_command_pool = VK_NULL_HANDLE;
+    VkCommandPoolCreateInfo command_pool_info;
+    VkDevice vk_device = device->vk_device;
+    VkCommandBufferBeginInfo begin_info;
+    VkCommandBuffer vk_command_buffer;
+    VkFence vk_fence = VK_NULL_HANDLE;
+    VkImageSubresourceRange range;
+    VkImageMemoryBarrier barrier;
+    VkFenceCreateInfo fence_info;
+    struct vkd3d_queue *queue;
+    VkSubmitInfo submit_info;
+    VkQueue vk_queue;
+    VkResult vr;
+
+    queue = d3d12_device_get_vkd3d_queue(device, D3D12_COMMAND_LIST_TYPE_DIRECT);
+
+    command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    command_pool_info.pNext = NULL;
+    command_pool_info.flags = 0;
+    command_pool_info.queueFamilyIndex = queue->vk_family_index;
+
+    if ((vr = VK_CALL(vkCreateCommandPool(vk_device, &command_pool_info, NULL, &vk_command_pool))) < 0)
+    {
+        WARN("Failed to create Vulkan command pool, vr %d.\n", vr);
+        goto done;
+    }
+
+    command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    command_buffer_info.pNext = NULL;
+    command_buffer_info.commandPool = vk_command_pool;
+    command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    command_buffer_info.commandBufferCount = 1;
+
+    if ((vr = VK_CALL(vkAllocateCommandBuffers(vk_device, &command_buffer_info, &vk_command_buffer))) < 0)
+    {
+        WARN("Failed to allocate Vulkan command buffer, vr %d.\n", vr);
+        goto done;
+    }
+
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    begin_info.pNext = NULL;
+    begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    begin_info.pInheritanceInfo = NULL;
+
+    if ((vr = VK_CALL(vkBeginCommandBuffer(vk_command_buffer, &begin_info))) < 0)
+    {
+        WARN("Failed to begin command buffer, vr %d.\n", vr);
+        goto done;
+    }
+
+    /* fill buffer */
+    VK_CALL(vkCmdFillBuffer(vk_command_buffer, null_resource->vk_buffer, 0, VK_WHOLE_SIZE, 0x00000000));
+
+    if (use_sparse_resources)
+    {
+        /* transition 2D UAV image */
+        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+        barrier.pNext = NULL;
+        barrier.srcAccessMask = 0;
+        barrier.dstAccessMask = 0;
+        barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
+        barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.image = null_resource->vk_2d_storage_image;
+        barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+        barrier.subresourceRange.baseMipLevel = 0;
+        barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+        barrier.subresourceRange.baseArrayLayer = 0;
+        barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+
+        VK_CALL(vkCmdPipelineBarrier(vk_command_buffer,
+                VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
+                0, NULL, 0, NULL, 1, &barrier));
+    }
+    else
+    {
+        /* fill UAV buffer */
+        VK_CALL(vkCmdFillBuffer(vk_command_buffer,
+                null_resource->vk_storage_buffer, 0, VK_WHOLE_SIZE, 0x00000000));
+
+        /* clear 2D UAV image */
+        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+        barrier.pNext = NULL;
+        barrier.srcAccessMask = 0;
+        barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+        barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
+        barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.image = null_resource->vk_2d_storage_image;
+        barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+        barrier.subresourceRange.baseMipLevel = 0;
+        barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+        barrier.subresourceRange.baseArrayLayer = 0;
+        barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+
+        VK_CALL(vkCmdPipelineBarrier(vk_command_buffer,
+                VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+                0, NULL, 0, NULL, 1, &barrier));
+
+        range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+        range.baseMipLevel = 0;
+        range.levelCount = 1;
+        range.baseArrayLayer = 0;
+        range.layerCount = 1;
+
+        VK_CALL(vkCmdClearColorImage(vk_command_buffer,
+                null_resource->vk_2d_storage_image, VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range));
+    }
+
+    /* transition 2D SRV image */
+    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barrier.pNext = NULL;
+    barrier.srcAccessMask = 0;
+    barrier.dstAccessMask = 0;
+    barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.image = null_resource->vk_2d_image;
+    barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    barrier.subresourceRange.baseMipLevel = 0;
+    barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+    barrier.subresourceRange.baseArrayLayer = 0;
+    barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+
+    VK_CALL(vkCmdPipelineBarrier(vk_command_buffer,
+            VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
+            0, NULL, 0, NULL, 1, &barrier));
+
+    if ((vr = VK_CALL(vkEndCommandBuffer(vk_command_buffer))) < 0)
+    {
+        WARN("Failed to end command buffer, vr %d.\n", vr);
+        goto done;
+    }
+
+    fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fence_info.pNext = NULL;
+    fence_info.flags = 0;
+
+    if ((vr = VK_CALL(vkCreateFence(device->vk_device, &fence_info, NULL, &vk_fence))) < 0)
+    {
+        WARN("Failed to create Vulkan fence, vr %d.\n", vr);
+        goto done;
+    }
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = NULL;
+    submit_info.waitSemaphoreCount = 0;
+    submit_info.pWaitSemaphores = NULL;
+    submit_info.pWaitDstStageMask = NULL;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &vk_command_buffer;
+    submit_info.signalSemaphoreCount = 0;
+    submit_info.pSignalSemaphores = NULL;
+
+    if (!(vk_queue = vkd3d_queue_acquire(queue)))
+    {
+        WARN("Failed to acquire queue %p.\n", queue);
+        goto done;
+    }
+
+    if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, vk_fence))) < 0)
+        ERR("Failed to submit, vr %d.\n", vr);
+
+    vkd3d_queue_release(queue);
+
+    vr = VK_CALL(vkWaitForFences(device->vk_device, 1, &vk_fence, VK_FALSE, ~(uint64_t)0));
+    if (vr != VK_SUCCESS)
+        WARN("Failed to wait for fence, vr %d.\n", vr);
+
+done:
+    VK_CALL(vkDestroyCommandPool(vk_device, vk_command_pool, NULL));
+    VK_CALL(vkDestroyFence(vk_device, vk_fence, NULL));
+
+    return hresult_from_vk_result(vr);
+}
+
+HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources,
+        struct d3d12_device *device)
+{
+    const bool use_sparse_resources = device->vk_info.sparse_properties.residencyNonResidentStrict;
+    D3D12_HEAP_PROPERTIES heap_properties;
+    D3D12_RESOURCE_DESC resource_desc;
+    HRESULT hr;
+
+    TRACE("Creating resources for NULL views.\n");
+
+    memset(null_resources, 0, sizeof(*null_resources));
+
+    memset(&heap_properties, 0, sizeof(heap_properties));
+    heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
+
+    /* buffer */
+    resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    resource_desc.Alignment = 0;
+    resource_desc.Width = VKD3D_NULL_BUFFER_SIZE;
+    resource_desc.Height = 1;
+    resource_desc.DepthOrArraySize = 1;
+    resource_desc.MipLevels = 1;
+    resource_desc.Format = DXGI_FORMAT_UNKNOWN;
+    resource_desc.SampleDesc.Count = 1;
+    resource_desc.SampleDesc.Quality = 0;
+    resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+    if (FAILED(hr = vkd3d_create_buffer(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
+            &resource_desc, &null_resources->vk_buffer)))
+        goto fail;
+    if (FAILED(hr = vkd3d_allocate_buffer_memory(device, null_resources->vk_buffer,
+            &heap_properties, D3D12_HEAP_FLAG_NONE, &null_resources->vk_buffer_memory, NULL, NULL)))
+        goto fail;
+
+    /* buffer UAV */
+    resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+
+    if (FAILED(hr = vkd3d_create_buffer(device, use_sparse_resources ? NULL : &heap_properties, D3D12_HEAP_FLAG_NONE,
+            &resource_desc, &null_resources->vk_storage_buffer)))
+        goto fail;
+    if (!use_sparse_resources && FAILED(hr = vkd3d_allocate_buffer_memory(device, null_resources->vk_storage_buffer,
+            &heap_properties, D3D12_HEAP_FLAG_NONE, &null_resources->vk_storage_buffer_memory, NULL, NULL)))
+        goto fail;
+
+    /* 2D SRV */
+    resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+    resource_desc.Alignment = 0;
+    resource_desc.Width = 1;
+    resource_desc.Height = 1;
+    resource_desc.DepthOrArraySize = 1;
+    resource_desc.MipLevels = 1;
+    resource_desc.Format = VKD3D_NULL_VIEW_FORMAT;
+    resource_desc.SampleDesc.Count = 1;
+    resource_desc.SampleDesc.Quality = 0;
+    resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+    resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+    if (FAILED(hr = vkd3d_create_image(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
+            &resource_desc, NULL, &null_resources->vk_2d_image)))
+        goto fail;
+    if (FAILED(hr = vkd3d_allocate_image_memory(device, null_resources->vk_2d_image,
+            &heap_properties, D3D12_HEAP_FLAG_NONE, &null_resources->vk_2d_image_memory, NULL, NULL)))
+        goto fail;
+
+    /* 2D UAV */
+    resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+    resource_desc.Alignment = 0;
+    resource_desc.Width = 1;
+    resource_desc.Height = 1;
+    resource_desc.DepthOrArraySize = 1;
+    resource_desc.MipLevels = 1;
+    resource_desc.Format = VKD3D_NULL_VIEW_FORMAT;
+    resource_desc.SampleDesc.Count = 1;
+    resource_desc.SampleDesc.Quality = 0;
+    resource_desc.Layout = use_sparse_resources
+            ? D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE : D3D12_TEXTURE_LAYOUT_UNKNOWN;
+    resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+
+    if (FAILED(hr = vkd3d_create_image(device, use_sparse_resources ? NULL : &heap_properties, D3D12_HEAP_FLAG_NONE,
+            &resource_desc, NULL, &null_resources->vk_2d_storage_image)))
+        goto fail;
+    if (!use_sparse_resources && FAILED(hr = vkd3d_allocate_image_memory(device, null_resources->vk_2d_storage_image,
+            &heap_properties, D3D12_HEAP_FLAG_NONE, &null_resources->vk_2d_storage_image_memory, NULL, NULL)))
+        goto fail;
+
+    /* set Vulkan object names */
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_buffer,
+            VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "NULL buffer");
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_buffer_memory,
+            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, "NULL memory");
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_storage_buffer,
+            VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "NULL UAV buffer");
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_2d_image,
+            VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "NULL 2D SRV image");
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_2d_image_memory,
+            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, "NULL 2D SRV memory");
+    vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_2d_storage_image,
+            VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "NULL 2D UAV image");
+    if (!use_sparse_resources)
+    {
+        vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_storage_buffer_memory,
+                VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, "NULL UAV buffer memory");
+        vkd3d_set_vk_object_name_utf8(device, (uint64_t)null_resources->vk_2d_storage_image_memory,
+                VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, "NULL 2D UAV memory");
+    }
+
+    return vkd3d_init_null_resources_data(null_resources, device);
+
+fail:
+    ERR("Failed to initialize NULL resources, hr %#x.\n", hr);
+    vkd3d_destroy_null_resources(null_resources, device);
+    return hr;
+}
+
+void vkd3d_destroy_null_resources(struct vkd3d_null_resources *null_resources,
+        struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    VK_CALL(vkDestroyBuffer(device->vk_device, null_resources->vk_buffer, NULL));
+    VK_CALL(vkFreeMemory(device->vk_device, null_resources->vk_buffer_memory, NULL));
+
+    VK_CALL(vkDestroyBuffer(device->vk_device, null_resources->vk_storage_buffer, NULL));
+    VK_CALL(vkFreeMemory(device->vk_device, null_resources->vk_storage_buffer_memory, NULL));
+
+    VK_CALL(vkDestroyImage(device->vk_device, null_resources->vk_2d_image, NULL));
+    VK_CALL(vkFreeMemory(device->vk_device, null_resources->vk_2d_image_memory, NULL));
+
+    VK_CALL(vkDestroyImage(device->vk_device, null_resources->vk_2d_storage_image, NULL));
+    VK_CALL(vkFreeMemory(device->vk_device, null_resources->vk_2d_storage_image_memory, NULL));
+
+    memset(null_resources, 0, sizeof(*null_resources));
+}
diff --git a/dlls/vkd3d/libs/vkd3d/state.c b/dlls/vkd3d/libs/vkd3d/state.c
new file mode 100644
index 00000000000..81f33435eb5
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/state.c
@@ -0,0 +1,3020 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ * Copyright 2016 Henri Verbeet for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_private.h"
+#include "vkd3d_shaders.h"
+
+/* ID3D12RootSignature */
+static inline struct d3d12_root_signature *impl_from_ID3D12RootSignature(ID3D12RootSignature *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_root_signature, ID3D12RootSignature_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_QueryInterface(ID3D12RootSignature *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12RootSignature)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12RootSignature_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_root_signature_AddRef(ID3D12RootSignature *iface)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+    ULONG refcount = InterlockedIncrement(&root_signature->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", root_signature, refcount);
+
+    return refcount;
+}
+
+static void d3d12_root_signature_cleanup(struct d3d12_root_signature *root_signature,
+        struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int i;
+
+    if (root_signature->vk_pipeline_layout)
+        VK_CALL(vkDestroyPipelineLayout(device->vk_device, root_signature->vk_pipeline_layout, NULL));
+    if (root_signature->vk_set_layout)
+        VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, root_signature->vk_set_layout, NULL));
+    if (root_signature->vk_push_set_layout)
+        VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, root_signature->vk_push_set_layout, NULL));
+
+    if (root_signature->parameters)
+    {
+        for (i = 0; i < root_signature->parameter_count; ++i)
+        {
+            if (root_signature->parameters[i].parameter_type == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+                vkd3d_free(root_signature->parameters[i].u.descriptor_table.ranges);
+        }
+        vkd3d_free(root_signature->parameters);
+    }
+
+    if (root_signature->descriptor_mapping)
+        vkd3d_free(root_signature->descriptor_mapping);
+    if (root_signature->root_constants)
+        vkd3d_free(root_signature->root_constants);
+
+    for (i = 0; i < root_signature->static_sampler_count; ++i)
+    {
+        if (root_signature->static_samplers[i])
+            VK_CALL(vkDestroySampler(device->vk_device, root_signature->static_samplers[i], NULL));
+    }
+    if (root_signature->static_samplers)
+        vkd3d_free(root_signature->static_samplers);
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_root_signature_Release(ID3D12RootSignature *iface)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+    ULONG refcount = InterlockedDecrement(&root_signature->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", root_signature, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = root_signature->device;
+        vkd3d_private_store_destroy(&root_signature->private_store);
+        d3d12_root_signature_cleanup(root_signature, device);
+        vkd3d_free(root_signature);
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_GetPrivateData(ID3D12RootSignature *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&root_signature->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_SetPrivateData(ID3D12RootSignature *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&root_signature->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_SetPrivateDataInterface(ID3D12RootSignature *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&root_signature->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_SetName(ID3D12RootSignature *iface, const WCHAR *name)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, root_signature->device->wchar_size));
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_GetDevice(ID3D12RootSignature *iface,
+        REFIID iid, void **device)
+{
+    struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(root_signature->device, iid, device);
+}
+
+static const struct ID3D12RootSignatureVtbl d3d12_root_signature_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_root_signature_QueryInterface,
+    d3d12_root_signature_AddRef,
+    d3d12_root_signature_Release,
+    /* ID3D12Object methods */
+    d3d12_root_signature_GetPrivateData,
+    d3d12_root_signature_SetPrivateData,
+    d3d12_root_signature_SetPrivateDataInterface,
+    d3d12_root_signature_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_root_signature_GetDevice,
+};
+
+struct d3d12_root_signature *unsafe_impl_from_ID3D12RootSignature(ID3D12RootSignature *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_root_signature_vtbl);
+    return impl_from_ID3D12RootSignature(iface);
+}
+
+static VkShaderStageFlags stage_flags_from_visibility(D3D12_SHADER_VISIBILITY visibility)
+{
+    switch (visibility)
+    {
+        case D3D12_SHADER_VISIBILITY_ALL:
+            return VK_SHADER_STAGE_ALL;
+        case D3D12_SHADER_VISIBILITY_VERTEX:
+            return VK_SHADER_STAGE_VERTEX_BIT;
+        case D3D12_SHADER_VISIBILITY_HULL:
+            return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+        case D3D12_SHADER_VISIBILITY_DOMAIN:
+            return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+        case D3D12_SHADER_VISIBILITY_GEOMETRY:
+            return VK_SHADER_STAGE_GEOMETRY_BIT;
+        case D3D12_SHADER_VISIBILITY_PIXEL:
+            return VK_SHADER_STAGE_FRAGMENT_BIT;
+        default:
+            return 0;
+    }
+}
+
+static enum vkd3d_shader_visibility vkd3d_shader_visibility_from_d3d12(D3D12_SHADER_VISIBILITY visibility)
+{
+    switch (visibility)
+    {
+        case D3D12_SHADER_VISIBILITY_ALL:
+            return VKD3D_SHADER_VISIBILITY_ALL;
+        case D3D12_SHADER_VISIBILITY_VERTEX:
+            return VKD3D_SHADER_VISIBILITY_VERTEX;
+        case D3D12_SHADER_VISIBILITY_HULL:
+            return VKD3D_SHADER_VISIBILITY_HULL;
+        case D3D12_SHADER_VISIBILITY_DOMAIN:
+            return VKD3D_SHADER_VISIBILITY_DOMAIN;
+        case D3D12_SHADER_VISIBILITY_GEOMETRY:
+            return VKD3D_SHADER_VISIBILITY_GEOMETRY;
+        case D3D12_SHADER_VISIBILITY_PIXEL:
+            return VKD3D_SHADER_VISIBILITY_PIXEL;
+        default:
+            FIXME("Unhandled visibility %#x.\n", visibility);
+            return VKD3D_SHADER_VISIBILITY_ALL;
+    }
+}
+
+static VkDescriptorType vk_descriptor_type_from_d3d12_range_type(D3D12_DESCRIPTOR_RANGE_TYPE type,
+        bool is_buffer)
+{
+    switch (type)
+    {
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
+            return is_buffer ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
+            return is_buffer ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
+            return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
+            return VK_DESCRIPTOR_TYPE_SAMPLER;
+        default:
+            FIXME("Unhandled descriptor range type type %#x.\n", type);
+            return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+    }
+}
+
+static VkDescriptorType vk_descriptor_type_from_d3d12_root_parameter(D3D12_ROOT_PARAMETER_TYPE type)
+{
+    switch (type)
+    {
+        /* SRV and UAV root parameters are buffer views. */
+        case D3D12_ROOT_PARAMETER_TYPE_SRV:
+            return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+        case D3D12_ROOT_PARAMETER_TYPE_UAV:
+            return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+        case D3D12_ROOT_PARAMETER_TYPE_CBV:
+            return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+        default:
+            FIXME("Unhandled descriptor root parameter type %#x.\n", type);
+            return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+    }
+}
+
+static enum vkd3d_shader_descriptor_type vkd3d_descriptor_type_from_d3d12_range_type(
+        D3D12_DESCRIPTOR_RANGE_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER;
+        default:
+            FIXME("Unhandled descriptor range type type %#x.\n", type);
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+    }
+}
+
+static enum vkd3d_shader_descriptor_type vkd3d_descriptor_type_from_d3d12_root_parameter_type(
+        D3D12_ROOT_PARAMETER_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_ROOT_PARAMETER_TYPE_SRV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+        case D3D12_ROOT_PARAMETER_TYPE_UAV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+        case D3D12_ROOT_PARAMETER_TYPE_CBV:
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+        default:
+            FIXME("Unhandled descriptor root parameter type %#x.\n", type);
+            return VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
+    }
+}
+
+static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutBinding *binding_desc,
+        const D3D12_DESCRIPTOR_RANGE *descriptor_range, D3D12_SHADER_VISIBILITY shader_visibility,
+        bool is_buffer, uint32_t vk_binding)
+{
+    binding_desc->binding = vk_binding;
+    binding_desc->descriptorType
+            = vk_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType, is_buffer);
+    binding_desc->descriptorCount = 1;
+    binding_desc->stageFlags = stage_flags_from_visibility(shader_visibility);
+    binding_desc->pImmutableSamplers = NULL;
+
+    return true;
+}
+
+struct d3d12_root_signature_info
+{
+    size_t cbv_count;
+    size_t buffer_uav_count;
+    size_t uav_count;
+    size_t buffer_srv_count;
+    size_t srv_count;
+    size_t sampler_count;
+
+    size_t descriptor_count;
+
+    size_t root_constant_count;
+    size_t root_descriptor_count;
+
+    size_t cost;
+};
+
+static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_signature_info *info,
+        const D3D12_DESCRIPTOR_RANGE *range)
+{
+    if (range->NumDescriptors == 0xffffffff)
+    {
+        FIXME("Unhandled unbound descriptor range.\n");
+        return E_NOTIMPL;
+    }
+
+    switch (range->RangeType)
+    {
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
+            info->srv_count += range->NumDescriptors;
+            break;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
+            info->uav_count += range->NumDescriptors;
+            break;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
+            info->cbv_count += range->NumDescriptors;
+            break;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
+            info->sampler_count += range->NumDescriptors;
+            break;
+        default:
+            FIXME("Unhandled descriptor type %#x.\n", range->RangeType);
+            return E_NOTIMPL;
+    }
+
+    info->descriptor_count += range->NumDescriptors;
+
+    return S_OK;
+}
+
+static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_info *info,
+        const D3D12_ROOT_SIGNATURE_DESC *desc)
+{
+    unsigned int i, j;
+    HRESULT hr;
+
+    memset(info, 0, sizeof(*info));
+
+    for (i = 0; i < desc->NumParameters; ++i)
+    {
+        const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i];
+
+        switch (p->ParameterType)
+        {
+            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                for (j = 0; j < p->u.DescriptorTable.NumDescriptorRanges; ++j)
+                    if (FAILED(hr = d3d12_root_signature_info_count_descriptors(info,
+                            &p->u.DescriptorTable.pDescriptorRanges[j])))
+                        return hr;
+                ++info->cost;
+                break;
+
+            case D3D12_ROOT_PARAMETER_TYPE_CBV:
+                ++info->root_descriptor_count;
+                ++info->cbv_count;
+                ++info->descriptor_count;
+                info->cost += 2;
+                break;
+            case D3D12_ROOT_PARAMETER_TYPE_SRV:
+                ++info->root_descriptor_count;
+                ++info->buffer_srv_count;
+                ++info->descriptor_count;
+                info->cost += 2;
+                break;
+            case D3D12_ROOT_PARAMETER_TYPE_UAV:
+                ++info->root_descriptor_count;
+                ++info->buffer_uav_count;
+                ++info->descriptor_count;
+                info->cost += 2;
+                break;
+
+            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                ++info->root_constant_count;
+                info->cost += p->u.Constants.Num32BitValues;
+                break;
+
+            default:
+                FIXME("Unhandled type %#x for parameter %u.\n", p->ParameterType, i);
+                return E_NOTIMPL;
+        }
+    }
+
+    info->sampler_count += desc->NumStaticSamplers;
+    info->descriptor_count += desc->NumStaticSamplers;
+
+    return S_OK;
+}
+
+static HRESULT d3d12_root_signature_init_push_constants(struct d3d12_root_signature *root_signature,
+        const D3D12_ROOT_SIGNATURE_DESC *desc, const struct d3d12_root_signature_info *info,
+        struct VkPushConstantRange push_constants[D3D12_SHADER_VISIBILITY_PIXEL + 1],
+        uint32_t *push_constant_range_count)
+{
+    uint32_t push_constants_offset[D3D12_SHADER_VISIBILITY_PIXEL + 1];
+    unsigned int i, j, push_constant_count;
+    uint32_t offset;
+
+    memset(push_constants, 0, (D3D12_SHADER_VISIBILITY_PIXEL + 1) * sizeof(*push_constants));
+    memset(push_constants_offset, 0, sizeof(push_constants_offset));
+    for (i = 0; i < desc->NumParameters; ++i)
+    {
+        const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i];
+        if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
+            continue;
+
+        assert(p->ShaderVisibility <= D3D12_SHADER_VISIBILITY_PIXEL);
+        push_constants[p->ShaderVisibility].stageFlags = stage_flags_from_visibility(p->ShaderVisibility);
+        push_constants[p->ShaderVisibility].size += p->u.Constants.Num32BitValues * sizeof(uint32_t);
+    }
+    if (push_constants[D3D12_SHADER_VISIBILITY_ALL].size)
+    {
+        /* When D3D12_SHADER_VISIBILITY_ALL is used we use a single push
+         * constants range because the Vulkan spec states:
+         *
+         *   "Any two elements of pPushConstantRanges must not include the same
+         *   stage in stageFlags".
+         */
+        push_constant_count = 1;
+        for (i = 0; i <= D3D12_SHADER_VISIBILITY_PIXEL; ++i)
+        {
+            if (i == D3D12_SHADER_VISIBILITY_ALL)
+                continue;
+
+            push_constants[D3D12_SHADER_VISIBILITY_ALL].size += push_constants[i].size;
+            push_constants[i].size = 0;
+        }
+    }
+    else
+    {
+        /* Move non-empty push constants ranges to front and compute offsets. */
+        offset = 0;
+        for (i = 0, j = 0; i <= D3D12_SHADER_VISIBILITY_PIXEL; ++i)
+        {
+            if (push_constants[i].size)
+            {
+                push_constants[j] = push_constants[i];
+                push_constants[j].offset = offset;
+                push_constants_offset[i] = offset;
+                offset += push_constants[j].size;
+                ++j;
+            }
+        }
+        push_constant_count = j;
+    }
+
+    for (i = 0, j = 0; i < desc->NumParameters; ++i)
+    {
+        struct d3d12_root_constant *root_constant = &root_signature->parameters[i].u.constant;
+        const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i];
+        unsigned int idx;
+
+        if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
+            continue;
+
+        idx = push_constant_count == 1 ? 0 : p->ShaderVisibility;
+        offset = push_constants_offset[idx];
+        push_constants_offset[idx] += p->u.Constants.Num32BitValues * sizeof(uint32_t);
+
+        root_signature->parameters[i].parameter_type = p->ParameterType;
+        root_constant->stage_flags = push_constant_count == 1
+                ? push_constants[0].stageFlags : stage_flags_from_visibility(p->ShaderVisibility);
+        root_constant->offset = offset;
+
+        root_signature->root_constants[j].register_space = p->u.Constants.RegisterSpace;
+        root_signature->root_constants[j].register_index = p->u.Constants.ShaderRegister;
+        root_signature->root_constants[j].shader_visibility
+                = vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility);
+        root_signature->root_constants[j].offset = offset;
+        root_signature->root_constants[j].size = p->u.Constants.Num32BitValues * sizeof(uint32_t);
+
+        ++j;
+    }
+
+    *push_constant_range_count = push_constant_count;
+
+    return S_OK;
+}
+
+struct vkd3d_descriptor_set_context
+{
+    VkDescriptorSetLayoutBinding *current_binding;
+    unsigned int descriptor_index;
+    uint32_t set_index;
+    uint32_t descriptor_binding;
+};
+
+static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature *root_signature,
+        enum vkd3d_shader_descriptor_type descriptor_type, unsigned int register_space, unsigned int register_idx,
+        bool buffer_descriptor, enum vkd3d_shader_visibility shader_visibility,
+        struct vkd3d_descriptor_set_context *context)
+{
+    struct vkd3d_shader_resource_binding *mapping
+            = &root_signature->descriptor_mapping[context->descriptor_index++];
+
+    mapping->type = descriptor_type;
+    mapping->register_space = register_space;
+    mapping->register_index = register_idx;
+    mapping->shader_visibility = shader_visibility;
+    mapping->flags = buffer_descriptor ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
+    mapping->binding.set = context->set_index;
+    mapping->binding.binding = context->descriptor_binding++;
+    mapping->binding.count = 1;
+}
+
+static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature,
+        enum vkd3d_shader_descriptor_type descriptor_type, unsigned int register_space, unsigned int base_register_idx,
+        unsigned int binding_count, bool is_buffer_descriptor, bool duplicate_descriptors,
+        enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context)
+{
+    uint32_t first_binding;
+    unsigned int i;
+
+    is_buffer_descriptor |= descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+    duplicate_descriptors = (descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV
+            || descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+            && duplicate_descriptors;
+
+    first_binding = context->descriptor_binding;
+    for (i = 0; i < binding_count; ++i)
+    {
+        if (duplicate_descriptors)
+            d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space,
+                    base_register_idx + i, true, shader_visibility, context);
+
+        d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space,
+                base_register_idx + i, is_buffer_descriptor, shader_visibility, context);
+    }
+    return first_binding;
+}
+
+static uint32_t vkd3d_descriptor_magic_from_d3d12(D3D12_DESCRIPTOR_RANGE_TYPE type)
+{
+    switch (type)
+    {
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
+            return VKD3D_DESCRIPTOR_MAGIC_SRV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
+            return VKD3D_DESCRIPTOR_MAGIC_UAV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
+            return VKD3D_DESCRIPTOR_MAGIC_CBV;
+        case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
+            return VKD3D_DESCRIPTOR_MAGIC_SAMPLER;
+        default:
+            ERR("Invalid range type %#x.\n", type);
+            return VKD3D_DESCRIPTOR_MAGIC_FREE;
+    }
+}
+
+static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature,
+        const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context)
+{
+    VkDescriptorSetLayoutBinding *cur_binding = context->current_binding;
+    struct d3d12_root_descriptor_table *table;
+    const D3D12_DESCRIPTOR_RANGE *range;
+    unsigned int i, j, k, range_count;
+    uint32_t vk_binding;
+
+    root_signature->descriptor_table_mask = 0;
+
+    for (i = 0; i < desc->NumParameters; ++i)
+    {
+        const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i];
+        if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            continue;
+
+        root_signature->descriptor_table_mask |= 1ull << i;
+
+        table = &root_signature->parameters[i].u.descriptor_table;
+        range_count = p->u.DescriptorTable.NumDescriptorRanges;
+
+        root_signature->parameters[i].parameter_type = p->ParameterType;
+        table->range_count = range_count;
+        if (!(table->ranges = vkd3d_calloc(table->range_count, sizeof(*table->ranges))))
+            return E_OUTOFMEMORY;
+
+        for (j = 0; j < range_count; ++j)
+        {
+            range = &p->u.DescriptorTable.pDescriptorRanges[j];
+
+            vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature,
+                    vkd3d_descriptor_type_from_d3d12_range_type(range->RangeType),
+                    range->RegisterSpace, range->BaseShaderRegister, range->NumDescriptors, false, true,
+                    vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), context);
+
+            /* Unroll descriptor range. */
+            for (k = 0; k < range->NumDescriptors; ++k)
+            {
+                uint32_t vk_current_binding = vk_binding + k;
+
+                if (range->RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV
+                        || range->RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
+                {
+                    vk_current_binding = vk_binding + 2 * k;
+
+                    /* Assign binding for image view. */
+                    if (!vk_binding_from_d3d12_descriptor_range(cur_binding,
+                            range, p->ShaderVisibility, false, vk_current_binding + 1))
+                        return E_NOTIMPL;
+
+                    ++cur_binding;
+                }
+
+                if (!vk_binding_from_d3d12_descriptor_range(cur_binding,
+                        range, p->ShaderVisibility, true, vk_current_binding))
+                    return E_NOTIMPL;
+
+                ++cur_binding;
+            }
+
+            table->ranges[j].offset = range->OffsetInDescriptorsFromTableStart;
+            table->ranges[j].descriptor_count = range->NumDescriptors;
+            table->ranges[j].binding = vk_binding;
+            table->ranges[j].descriptor_magic = vkd3d_descriptor_magic_from_d3d12(range->RangeType);
+            table->ranges[j].register_space = range->RegisterSpace;
+            table->ranges[j].base_register_idx = range->BaseShaderRegister;
+        }
+    }
+
+    context->current_binding = cur_binding;
+    return S_OK;
+}
+
+static HRESULT d3d12_root_signature_init_root_descriptors(struct d3d12_root_signature *root_signature,
+        const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context)
+{
+    VkDescriptorSetLayoutBinding *cur_binding = context->current_binding;
+    unsigned int i;
+
+    root_signature->push_descriptor_mask = 0;
+
+    for (i = 0; i < desc->NumParameters; ++i)
+    {
+        const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i];
+        if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_CBV
+                && p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_SRV
+                && p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_UAV)
+            continue;
+
+        root_signature->push_descriptor_mask |= 1u << i;
+
+        cur_binding->binding = d3d12_root_signature_assign_vk_bindings(root_signature,
+                vkd3d_descriptor_type_from_d3d12_root_parameter_type(p->ParameterType),
+                p->u.Descriptor.RegisterSpace, p->u.Descriptor.ShaderRegister, 1, true, false,
+                vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), context);
+        cur_binding->descriptorType = vk_descriptor_type_from_d3d12_root_parameter(p->ParameterType);
+        cur_binding->descriptorCount = 1;
+        cur_binding->stageFlags = stage_flags_from_visibility(p->ShaderVisibility);
+        cur_binding->pImmutableSamplers = NULL;
+
+        root_signature->parameters[i].parameter_type = p->ParameterType;
+        root_signature->parameters[i].u.descriptor.binding = cur_binding->binding;
+
+        ++cur_binding;
+    }
+
+    context->current_binding = cur_binding;
+    return S_OK;
+}
+
+static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signature *root_signature,
+        struct d3d12_device *device, const D3D12_ROOT_SIGNATURE_DESC *desc,
+        struct vkd3d_descriptor_set_context *context)
+{
+    VkDescriptorSetLayoutBinding *cur_binding = context->current_binding;
+    unsigned int i;
+    HRESULT hr;
+
+    assert(root_signature->static_sampler_count == desc->NumStaticSamplers);
+    for (i = 0; i < desc->NumStaticSamplers; ++i)
+    {
+        const D3D12_STATIC_SAMPLER_DESC *s = &desc->pStaticSamplers[i];
+
+        if (FAILED(hr = vkd3d_create_static_sampler(device, s, &root_signature->static_samplers[i])))
+            return hr;
+
+        cur_binding->binding = d3d12_root_signature_assign_vk_bindings(root_signature,
+                VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, s->RegisterSpace, s->ShaderRegister, 1, false, false,
+                vkd3d_shader_visibility_from_d3d12(s->ShaderVisibility), context);
+        cur_binding->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
+        cur_binding->descriptorCount = 1;
+        cur_binding->stageFlags = stage_flags_from_visibility(s->ShaderVisibility);
+        cur_binding->pImmutableSamplers = &root_signature->static_samplers[i];
+
+        ++cur_binding;
+    }
+
+    context->current_binding = cur_binding;
+    return S_OK;
+}
+
+static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
+        VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count,
+        const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkDescriptorSetLayoutCreateInfo set_desc;
+    VkResult vr;
+
+    set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    set_desc.pNext = NULL;
+    set_desc.flags = flags;
+    set_desc.bindingCount = binding_count;
+    set_desc.pBindings = bindings;
+    if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, set_layout))) < 0)
+    {
+        WARN("Failed to create Vulkan descriptor set layout, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    return S_OK;
+}
+
+static HRESULT vkd3d_create_pipeline_layout(struct d3d12_device *device,
+        unsigned int set_layout_count, const VkDescriptorSetLayout *set_layouts,
+        unsigned int push_constant_count, const VkPushConstantRange *push_constants,
+        VkPipelineLayout *pipeline_layout)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct VkPipelineLayoutCreateInfo pipeline_layout_info;
+    VkResult vr;
+
+    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipeline_layout_info.pNext = NULL;
+    pipeline_layout_info.flags = 0;
+    pipeline_layout_info.setLayoutCount = set_layout_count;
+    pipeline_layout_info.pSetLayouts = set_layouts;
+    pipeline_layout_info.pushConstantRangeCount = push_constant_count;
+    pipeline_layout_info.pPushConstantRanges = push_constants;
+    if ((vr = VK_CALL(vkCreatePipelineLayout(device->vk_device,
+            &pipeline_layout_info, NULL, pipeline_layout))) < 0)
+    {
+        WARN("Failed to create Vulkan pipeline layout, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    return S_OK;
+}
+
+static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signature,
+        struct d3d12_device *device, const D3D12_ROOT_SIGNATURE_DESC *desc)
+{
+    const struct vkd3d_vulkan_info *vk_info = &device->vk_info;
+    struct vkd3d_descriptor_set_context context;
+    VkDescriptorSetLayoutBinding *binding_desc;
+    struct d3d12_root_signature_info info;
+    VkDescriptorSetLayout set_layouts[2];
+    HRESULT hr;
+
+    memset(&context, 0, sizeof(context));
+    binding_desc = NULL;
+
+    root_signature->ID3D12RootSignature_iface.lpVtbl = &d3d12_root_signature_vtbl;
+    root_signature->refcount = 1;
+
+    root_signature->vk_pipeline_layout = VK_NULL_HANDLE;
+    root_signature->vk_push_set_layout = VK_NULL_HANDLE;
+    root_signature->vk_set_layout = VK_NULL_HANDLE;
+    root_signature->parameters = NULL;
+    root_signature->flags = desc->Flags;
+    root_signature->descriptor_mapping = NULL;
+    root_signature->static_sampler_count = 0;
+    root_signature->static_samplers = NULL;
+
+    if (desc->Flags & ~(D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
+            | D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT))
+        FIXME("Ignoring root signature flags %#x.\n", desc->Flags);
+
+    if (FAILED(hr = d3d12_root_signature_info_from_desc(&info, desc)))
+        return hr;
+    if (info.cost > D3D12_MAX_ROOT_COST)
+    {
+        WARN("Root signature cost %zu exceeds maximum allowed cost.\n", info.cost);
+        return E_INVALIDARG;
+    }
+
+    /* XXX: Vulkan buffer and image descriptors have different types. In order
+     * to preserve compatibility between Vulkan resource bindings for the same
+     * root signature, we create descriptor set layouts with two bindings for
+     * each SRV and UAV. */
+    info.descriptor_count += info.srv_count + info.uav_count;
+
+    root_signature->descriptor_count = info.descriptor_count;
+    root_signature->static_sampler_count = desc->NumStaticSamplers;
+    root_signature->root_descriptor_count = info.root_descriptor_count;
+
+    hr = E_OUTOFMEMORY;
+    root_signature->parameter_count = desc->NumParameters;
+    if (!(root_signature->parameters = vkd3d_calloc(root_signature->parameter_count,
+            sizeof(*root_signature->parameters))))
+        goto fail;
+    if (!(root_signature->descriptor_mapping = vkd3d_calloc(root_signature->descriptor_count,
+            sizeof(*root_signature->descriptor_mapping))))
+        goto fail;
+    root_signature->root_constant_count = info.root_constant_count;
+    if (!(root_signature->root_constants = vkd3d_calloc(root_signature->root_constant_count,
+            sizeof(*root_signature->root_constants))))
+        goto fail;
+    if (!(root_signature->static_samplers = vkd3d_calloc(root_signature->static_sampler_count,
+            sizeof(*root_signature->static_samplers))))
+        goto fail;
+
+    if (!(binding_desc = vkd3d_calloc(info.descriptor_count, sizeof(*binding_desc))))
+        goto fail;
+    context.current_binding = binding_desc;
+
+    if (FAILED(hr = d3d12_root_signature_init_root_descriptors(root_signature, desc, &context)))
+        goto fail;
+
+    /* We use KHR_push_descriptor for root descriptor parameters. */
+    if (vk_info->KHR_push_descriptor && context.descriptor_binding)
+    {
+        if (FAILED(hr = vkd3d_create_descriptor_set_layout(device,
+                VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
+                context.descriptor_binding, binding_desc, &root_signature->vk_push_set_layout)))
+            goto fail;
+
+        set_layouts[context.set_index++] = root_signature->vk_push_set_layout;
+        context.current_binding = binding_desc;
+        context.descriptor_binding = 0;
+    }
+
+    if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc, &info,
+            root_signature->push_constant_ranges, &root_signature->push_constant_range_count)))
+        goto fail;
+    if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context)))
+        goto fail;
+    if (FAILED(hr = d3d12_root_signature_init_static_samplers(root_signature, device, desc, &context)))
+        goto fail;
+
+    root_signature->main_set = context.set_index;
+    if (context.descriptor_binding)
+    {
+        if (FAILED(hr = vkd3d_create_descriptor_set_layout(device,
+                0, context.descriptor_binding, binding_desc, &root_signature->vk_set_layout)))
+            goto fail;
+
+        set_layouts[context.set_index++] = root_signature->vk_set_layout;
+    }
+    vkd3d_free(binding_desc);
+    binding_desc = NULL;
+
+    if (FAILED(hr = vkd3d_create_pipeline_layout(device, context.set_index, set_layouts,
+            root_signature->push_constant_range_count, root_signature->push_constant_ranges,
+            &root_signature->vk_pipeline_layout)))
+        goto fail;
+
+    if (FAILED(hr = vkd3d_private_store_init(&root_signature->private_store)))
+        goto fail;
+
+    d3d12_device_add_ref(root_signature->device = device);
+
+    return S_OK;
+
+fail:
+    vkd3d_free(binding_desc);
+    d3d12_root_signature_cleanup(root_signature, device);
+    return hr;
+}
+
+HRESULT d3d12_root_signature_create(struct d3d12_device *device,
+        const void *bytecode, size_t bytecode_length, struct d3d12_root_signature **root_signature)
+{
+    const struct vkd3d_shader_code dxbc = {bytecode, bytecode_length};
+    union
+    {
+        D3D12_VERSIONED_ROOT_SIGNATURE_DESC d3d12;
+        struct vkd3d_shader_versioned_root_signature_desc vkd3d;
+    } root_signature_desc;
+    struct d3d12_root_signature *object;
+    HRESULT hr;
+    int ret;
+
+    if ((ret = vkd3d_parse_root_signature_v_1_0(&dxbc, &root_signature_desc.vkd3d)) < 0)
+    {
+        WARN("Failed to parse root signature, vkd3d result %d.\n", ret);
+        return hresult_from_vkd3d_result(ret);
+    }
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+    {
+        vkd3d_shader_free_root_signature(&root_signature_desc.vkd3d);
+        return E_OUTOFMEMORY;
+    }
+
+    hr = d3d12_root_signature_init(object, device, &root_signature_desc.d3d12.u.Desc_1_0);
+    vkd3d_shader_free_root_signature(&root_signature_desc.vkd3d);
+    if (FAILED(hr))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created root signature %p.\n", object);
+
+    *root_signature = object;
+
+    return S_OK;
+}
+
+/* vkd3d_render_pass_cache */
+struct vkd3d_render_pass_entry
+{
+    struct vkd3d_render_pass_key key;
+    VkRenderPass vk_render_pass;
+};
+
+STATIC_ASSERT(sizeof(struct vkd3d_render_pass_key) == 48);
+
+static HRESULT vkd3d_render_pass_cache_create_pass_locked(struct vkd3d_render_pass_cache *cache,
+        struct d3d12_device *device, const struct vkd3d_render_pass_key *key, VkRenderPass *vk_render_pass)
+{
+    VkAttachmentReference attachment_references[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
+    VkAttachmentDescription attachments[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_render_pass_entry *entry;
+    unsigned int index, attachment_index;
+    VkSubpassDescription sub_pass_desc;
+    VkRenderPassCreateInfo pass_info;
+    bool have_depth_stencil;
+    unsigned int rt_count;
+    VkResult vr;
+
+    if (!vkd3d_array_reserve((void **)&cache->render_passes, &cache->render_passes_size,
+            cache->render_pass_count + 1, sizeof(*cache->render_passes)))
+    {
+        *vk_render_pass = VK_NULL_HANDLE;
+        return E_OUTOFMEMORY;
+    }
+
+    entry = &cache->render_passes[cache->render_pass_count];
+
+    entry->key = *key;
+
+    have_depth_stencil = key->depth_enable || key->stencil_enable;
+    rt_count = have_depth_stencil ? key->attachment_count - 1 : key->attachment_count;
+    assert(rt_count <= D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
+
+    for (index = 0, attachment_index = 0; index < rt_count; ++index)
+    {
+        if (!key->vk_formats[index])
+        {
+            attachment_references[index].attachment = VK_ATTACHMENT_UNUSED;
+            attachment_references[index].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+            continue;
+        }
+
+        attachments[attachment_index].flags = 0;
+        attachments[attachment_index].format = key->vk_formats[index];
+        attachments[attachment_index].samples = key->sample_count;
+        attachments[attachment_index].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+        attachments[attachment_index].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+        attachments[attachment_index].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+        attachments[attachment_index].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+        attachments[attachment_index].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+        attachments[attachment_index].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        attachment_references[index].attachment = attachment_index;
+        attachment_references[index].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        ++attachment_index;
+    }
+
+    if (have_depth_stencil)
+    {
+        VkImageLayout depth_layout = key->depth_stencil_write
+                ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+                : VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
+
+        attachments[attachment_index].flags = 0;
+        attachments[attachment_index].format = key->vk_formats[index];
+        attachments[attachment_index].samples = key->sample_count;
+
+        if (key->depth_enable)
+        {
+            attachments[attachment_index].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+            attachments[attachment_index].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+        }
+        else
+        {
+            attachments[attachment_index].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+            attachments[attachment_index].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+        }
+        if (key->stencil_enable)
+        {
+            attachments[attachment_index].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+            attachments[attachment_index].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+        }
+        else
+        {
+            attachments[attachment_index].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+            attachments[attachment_index].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+        }
+        attachments[attachment_index].initialLayout = depth_layout;
+        attachments[attachment_index].finalLayout = depth_layout;
+
+        attachment_references[index].attachment = attachment_index;
+        attachment_references[index].layout = depth_layout;
+
+        attachment_index++;
+    }
+
+    sub_pass_desc.flags = 0;
+    sub_pass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    sub_pass_desc.inputAttachmentCount = 0;
+    sub_pass_desc.pInputAttachments = NULL;
+    sub_pass_desc.colorAttachmentCount = rt_count;
+    sub_pass_desc.pColorAttachments = attachment_references;
+    sub_pass_desc.pResolveAttachments = NULL;
+    if (have_depth_stencil)
+        sub_pass_desc.pDepthStencilAttachment = &attachment_references[rt_count];
+    else
+        sub_pass_desc.pDepthStencilAttachment = NULL;
+    sub_pass_desc.preserveAttachmentCount = 0;
+    sub_pass_desc.pPreserveAttachments = NULL;
+
+    pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    pass_info.pNext = NULL;
+    pass_info.flags = 0;
+    pass_info.attachmentCount = attachment_index;
+    pass_info.pAttachments = attachments;
+    pass_info.subpassCount = 1;
+    pass_info.pSubpasses = &sub_pass_desc;
+    pass_info.dependencyCount = 0;
+    pass_info.pDependencies = NULL;
+    if ((vr = VK_CALL(vkCreateRenderPass(device->vk_device, &pass_info, NULL, vk_render_pass))) >= 0)
+    {
+        entry->vk_render_pass = *vk_render_pass;
+        ++cache->render_pass_count;
+    }
+    else
+    {
+        WARN("Failed to create Vulkan render pass, vr %d.\n", vr);
+        *vk_render_pass = VK_NULL_HANDLE;
+    }
+
+    return hresult_from_vk_result(vr);
+}
+
+HRESULT vkd3d_render_pass_cache_find(struct vkd3d_render_pass_cache *cache,
+        struct d3d12_device *device, const struct vkd3d_render_pass_key *key, VkRenderPass *vk_render_pass)
+{
+    bool found = false;
+    HRESULT hr = S_OK;
+    unsigned int i;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&device->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        *vk_render_pass = VK_NULL_HANDLE;
+        return hresult_from_errno(rc);
+    }
+
+    for (i = 0; i < cache->render_pass_count; ++i)
+    {
+        struct vkd3d_render_pass_entry *current = &cache->render_passes[i];
+
+        if (!memcmp(&current->key, key, sizeof(*key)))
+        {
+            *vk_render_pass = current->vk_render_pass;
+            found = true;
+            break;
+        }
+    }
+
+    if (!found)
+        hr = vkd3d_render_pass_cache_create_pass_locked(cache, device, key, vk_render_pass);
+
+    pthread_mutex_unlock(&device->mutex);
+
+    return hr;
+}
+
+void vkd3d_render_pass_cache_init(struct vkd3d_render_pass_cache *cache)
+{
+    cache->render_passes = NULL;
+    cache->render_pass_count = 0;
+    cache->render_passes_size = 0;
+}
+
+void vkd3d_render_pass_cache_cleanup(struct vkd3d_render_pass_cache *cache,
+        struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    unsigned int i;
+
+    for (i = 0; i < cache->render_pass_count; ++i)
+    {
+        struct vkd3d_render_pass_entry *current = &cache->render_passes[i];
+        VK_CALL(vkDestroyRenderPass(device->vk_device, current->vk_render_pass, NULL));
+    }
+
+    vkd3d_free(cache->render_passes);
+    cache->render_passes = NULL;
+}
+
+struct vkd3d_pipeline_key
+{
+    D3D12_PRIMITIVE_TOPOLOGY topology;
+    uint32_t strides[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    VkFormat dsv_format;
+};
+
+struct vkd3d_compiled_pipeline
+{
+    struct list entry;
+    struct vkd3d_pipeline_key key;
+    VkPipeline vk_pipeline;
+    VkRenderPass vk_render_pass;
+};
+
+/* ID3D12PipelineState */
+static inline struct d3d12_pipeline_state *impl_from_ID3D12PipelineState(ID3D12PipelineState *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_pipeline_state, ID3D12PipelineState_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_QueryInterface(ID3D12PipelineState *iface,
+        REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3D12PipelineState)
+            || IsEqualGUID(riid, &IID_ID3D12Pageable)
+            || IsEqualGUID(riid, &IID_ID3D12DeviceChild)
+            || IsEqualGUID(riid, &IID_ID3D12Object)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D12PipelineState_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_pipeline_state_AddRef(ID3D12PipelineState *iface)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+    ULONG refcount = InterlockedIncrement(&state->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", state, refcount);
+
+    return refcount;
+}
+
+static void d3d12_pipeline_state_destroy_graphics(struct d3d12_pipeline_state *state,
+        struct d3d12_device *device)
+{
+    struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_compiled_pipeline *current, *e;
+    unsigned int i;
+
+    for (i = 0; i < graphics->stage_count; ++i)
+    {
+        VK_CALL(vkDestroyShaderModule(device->vk_device, graphics->stages[i].module, NULL));
+    }
+
+    LIST_FOR_EACH_ENTRY_SAFE(current, e, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
+    {
+        VK_CALL(vkDestroyPipeline(device->vk_device, current->vk_pipeline, NULL));
+        vkd3d_free(current);
+    }
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_pipeline_state_Release(ID3D12PipelineState *iface)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+    ULONG refcount = InterlockedDecrement(&state->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", state, refcount);
+
+    if (!refcount)
+    {
+        struct d3d12_device *device = state->device;
+        const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+        vkd3d_private_store_destroy(&state->private_store);
+
+        if (d3d12_pipeline_state_is_graphics(state))
+            d3d12_pipeline_state_destroy_graphics(state, device);
+        else if (d3d12_pipeline_state_is_compute(state))
+            VK_CALL(vkDestroyPipeline(device->vk_device, state->u.compute.vk_pipeline, NULL));
+
+        if (state->vk_set_layout)
+            VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout, NULL));
+        if (state->vk_pipeline_layout)
+            VK_CALL(vkDestroyPipelineLayout(device->vk_device, state->vk_pipeline_layout, NULL));
+
+        vkd3d_free(state->uav_counters);
+
+        vkd3d_free(state);
+
+        d3d12_device_release(device);
+    }
+
+    return refcount;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_GetPrivateData(ID3D12PipelineState *iface,
+        REFGUID guid, UINT *data_size, void *data)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_get_private_data(&state->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_SetPrivateData(ID3D12PipelineState *iface,
+        REFGUID guid, UINT data_size, const void *data)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return vkd3d_set_private_data(&state->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_SetPrivateDataInterface(ID3D12PipelineState *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return vkd3d_set_private_data_interface(&state->private_store, guid, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_SetName(ID3D12PipelineState *iface, const WCHAR *name)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name, state->device->wchar_size));
+
+    if (d3d12_pipeline_state_is_compute(state))
+    {
+        return vkd3d_set_vk_object_name(state->device, (uint64_t)state->u.compute.vk_pipeline,
+                VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, name);
+    }
+
+    return name ? S_OK : E_INVALIDARG;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_GetDevice(ID3D12PipelineState *iface,
+        REFIID iid, void **device)
+{
+    struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
+
+    TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
+
+    return d3d12_device_query_interface(state->device, iid, device);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_GetCachedBlob(ID3D12PipelineState *iface,
+        ID3DBlob **blob)
+{
+    FIXME("iface %p, blob %p stub!\n", iface, blob);
+
+    return E_NOTIMPL;
+}
+
+static const struct ID3D12PipelineStateVtbl d3d12_pipeline_state_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_pipeline_state_QueryInterface,
+    d3d12_pipeline_state_AddRef,
+    d3d12_pipeline_state_Release,
+    /* ID3D12Object methods */
+    d3d12_pipeline_state_GetPrivateData,
+    d3d12_pipeline_state_SetPrivateData,
+    d3d12_pipeline_state_SetPrivateDataInterface,
+    d3d12_pipeline_state_SetName,
+    /* ID3D12DeviceChild methods */
+    d3d12_pipeline_state_GetDevice,
+    /* ID3D12PipelineState methods */
+    d3d12_pipeline_state_GetCachedBlob,
+};
+
+struct d3d12_pipeline_state *unsafe_impl_from_ID3D12PipelineState(ID3D12PipelineState *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d12_pipeline_state_vtbl);
+    return impl_from_ID3D12PipelineState(iface);
+}
+
+static HRESULT create_shader_stage(struct d3d12_device *device,
+        struct VkPipelineShaderStageCreateInfo *stage_desc, enum VkShaderStageFlagBits stage,
+        const D3D12_SHADER_BYTECODE *code, const struct vkd3d_shader_interface_info *shader_interface)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_shader_compile_info compile_info;
+    struct VkShaderModuleCreateInfo shader_desc;
+    struct vkd3d_shader_code spirv = {0};
+    VkResult vr;
+    int ret;
+
+    stage_desc->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    stage_desc->pNext = NULL;
+    stage_desc->flags = 0;
+    stage_desc->stage = stage;
+    stage_desc->pName = "main";
+    stage_desc->pSpecializationInfo = NULL;
+
+    shader_desc.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    shader_desc.pNext = NULL;
+    shader_desc.flags = 0;
+
+    compile_info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO;
+    compile_info.next = shader_interface;
+    compile_info.source.code = code->pShaderBytecode;
+    compile_info.source.size = code->BytecodeLength;
+    compile_info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
+    compile_info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
+    compile_info.options = NULL;
+    compile_info.option_count = 0;
+    compile_info.log_level = VKD3D_SHADER_LOG_NONE;
+    compile_info.source_name = NULL;
+
+    if ((ret = vkd3d_shader_compile(&compile_info, &spirv, NULL)) < 0)
+    {
+        WARN("Failed to compile shader, vkd3d result %d.\n", ret);
+        return hresult_from_vkd3d_result(ret);
+    }
+    shader_desc.codeSize = spirv.size;
+    shader_desc.pCode = spirv.code;
+
+    vr = VK_CALL(vkCreateShaderModule(device->vk_device, &shader_desc, NULL, &stage_desc->module));
+    vkd3d_shader_free_shader_code(&spirv);
+    if (vr < 0)
+    {
+        WARN("Failed to create Vulkan shader module, vr %d.\n", vr);
+        return hresult_from_vk_result(vr);
+    }
+
+    return S_OK;
+}
+
+static int vkd3d_scan_dxbc(const D3D12_SHADER_BYTECODE *code,
+        struct vkd3d_shader_scan_descriptor_info *descriptor_info)
+{
+    struct vkd3d_shader_compile_info compile_info;
+
+    compile_info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO;
+    compile_info.next = descriptor_info;
+    compile_info.source.code = code->pShaderBytecode;
+    compile_info.source.size = code->BytecodeLength;
+    compile_info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
+    compile_info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
+    compile_info.options = NULL;
+    compile_info.option_count = 0;
+    compile_info.log_level = VKD3D_SHADER_LOG_NONE;
+    compile_info.source_name = NULL;
+
+    return vkd3d_shader_scan(&compile_info, NULL);
+}
+
+static HRESULT vkd3d_create_compute_pipeline(struct d3d12_device *device,
+        const D3D12_SHADER_BYTECODE *code, const struct vkd3d_shader_interface_info *shader_interface,
+        VkPipelineLayout vk_pipeline_layout, VkPipeline *vk_pipeline)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkComputePipelineCreateInfo pipeline_info;
+    VkResult vr;
+    HRESULT hr;
+
+    pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+    pipeline_info.pNext = NULL;
+    pipeline_info.flags = 0;
+    if (FAILED(hr = create_shader_stage(device, &pipeline_info.stage,
+            VK_SHADER_STAGE_COMPUTE_BIT, code, shader_interface)))
+        return hr;
+    pipeline_info.layout = vk_pipeline_layout;
+    pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
+    pipeline_info.basePipelineIndex = -1;
+
+    vr = VK_CALL(vkCreateComputePipelines(device->vk_device,
+            VK_NULL_HANDLE, 1, &pipeline_info, NULL, vk_pipeline));
+    VK_CALL(vkDestroyShaderModule(device->vk_device, pipeline_info.stage.module, NULL));
+    if (vr < 0)
+    {
+        WARN("Failed to create Vulkan compute pipeline, hr %#x.", hr);
+        return hresult_from_vk_result(vr);
+    }
+
+    return S_OK;
+}
+
+static HRESULT d3d12_pipeline_state_init_compute_uav_counters(struct d3d12_pipeline_state *state,
+        struct d3d12_device *device, const struct d3d12_root_signature *root_signature,
+        const struct vkd3d_shader_scan_descriptor_info *shader_info)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_descriptor_set_context context;
+    VkDescriptorSetLayoutBinding *binding_desc;
+    VkDescriptorSetLayout set_layouts[3];
+    unsigned int uav_counter_count = 0;
+    unsigned int i, j;
+    HRESULT hr;
+
+    for (i = 0; i < shader_info->descriptor_count; ++i)
+    {
+        const struct vkd3d_shader_descriptor_info *d = &shader_info->descriptors[i];
+
+        if (d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV
+                && (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER))
+            ++uav_counter_count;
+    }
+
+    if (!uav_counter_count)
+        return S_OK;
+
+    if (!(binding_desc = vkd3d_calloc(uav_counter_count, sizeof(*binding_desc))))
+        return E_OUTOFMEMORY;
+    if (!(state->uav_counters = vkd3d_calloc(uav_counter_count, sizeof(*state->uav_counters))))
+    {
+        vkd3d_free(binding_desc);
+        return E_OUTOFMEMORY;
+    }
+    state->uav_counter_count = uav_counter_count;
+
+    memset(&context, 0, sizeof(context));
+    if (root_signature->vk_push_set_layout)
+        set_layouts[context.set_index++] = root_signature->vk_push_set_layout;
+    if (root_signature->vk_set_layout)
+        set_layouts[context.set_index++] = root_signature->vk_set_layout;
+
+    for (i = 0, j = 0; i < shader_info->descriptor_count; ++i)
+    {
+        const struct vkd3d_shader_descriptor_info *d = &shader_info->descriptors[i];
+
+        if (d->type != VKD3D_SHADER_DESCRIPTOR_TYPE_UAV
+                || !(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER))
+            continue;
+
+        state->uav_counters[j].register_space = d->register_space;
+        state->uav_counters[j].register_index = d->register_index;
+        state->uav_counters[j].shader_visibility = VKD3D_SHADER_VISIBILITY_COMPUTE;
+        state->uav_counters[j].binding.set = context.set_index;
+        state->uav_counters[j].binding.binding = context.descriptor_binding;
+        state->uav_counters[j].binding.count = 1;
+
+        /* FIXME: For the graphics pipeline we have to take the shader
+         * visibility into account. */
+        binding_desc[j].binding = context.descriptor_binding;
+        binding_desc[j].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+        binding_desc[j].descriptorCount = 1;
+        binding_desc[j].stageFlags = VK_SHADER_STAGE_ALL;
+        binding_desc[j].pImmutableSamplers = NULL;
+
+        ++context.descriptor_binding;
+        ++j;
+    }
+
+    /* Create a descriptor set layout for UAV counters. */
+    hr = vkd3d_create_descriptor_set_layout(device,
+            0, context.descriptor_binding, binding_desc, &state->vk_set_layout);
+    vkd3d_free(binding_desc);
+    if (FAILED(hr))
+    {
+        vkd3d_free(state->uav_counters);
+        return hr;
+    }
+
+    /* Create a pipeline layout which is compatible for all other descriptor
+     * sets with the root signature's pipeline layout.
+     */
+    state->set_index = context.set_index;
+    set_layouts[context.set_index++] = state->vk_set_layout;
+    if (FAILED(hr = vkd3d_create_pipeline_layout(device, context.set_index, set_layouts,
+            root_signature->push_constant_range_count, root_signature->push_constant_ranges,
+            &state->vk_pipeline_layout)))
+    {
+        VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout, NULL));
+        vkd3d_free(state->uav_counters);
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *state,
+        struct d3d12_device *device, const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_shader_scan_descriptor_info shader_info;
+    struct vkd3d_shader_interface_info shader_interface;
+    const struct d3d12_root_signature *root_signature;
+    VkPipelineLayout vk_pipeline_layout;
+    HRESULT hr;
+    int ret;
+
+    state->ID3D12PipelineState_iface.lpVtbl = &d3d12_pipeline_state_vtbl;
+    state->refcount = 1;
+
+    state->vk_pipeline_layout = VK_NULL_HANDLE;
+    state->vk_set_layout = VK_NULL_HANDLE;
+    state->uav_counters = NULL;
+    state->uav_counter_count = 0;
+
+    if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->pRootSignature)))
+    {
+        WARN("Root signature is NULL.\n");
+        return E_INVALIDARG;
+    }
+
+    shader_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO;
+    shader_info.next = NULL;
+    if ((ret = vkd3d_scan_dxbc(&desc->CS, &shader_info)) < 0)
+    {
+        WARN("Failed to scan shader bytecode, vkd3d result %d.\n", ret);
+        return hresult_from_vkd3d_result(ret);
+    }
+
+    if (FAILED(hr = d3d12_pipeline_state_init_compute_uav_counters(state,
+            device, root_signature, &shader_info)))
+    {
+        WARN("Failed to create descriptor set layout for UAV counters, hr %#x.\n", hr);
+        return hr;
+    }
+    vkd3d_shader_free_scan_descriptor_info(&shader_info);
+
+    shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO;
+    shader_interface.next = NULL;
+    shader_interface.bindings = root_signature->descriptor_mapping;
+    shader_interface.binding_count = root_signature->descriptor_count;
+    shader_interface.push_constant_buffers = root_signature->root_constants;
+    shader_interface.push_constant_buffer_count = root_signature->root_constant_count;
+    shader_interface.combined_samplers = NULL;
+    shader_interface.combined_sampler_count = 0;
+    shader_interface.uav_counters = state->uav_counters;
+    shader_interface.uav_counter_count = state->uav_counter_count;
+
+    vk_pipeline_layout = state->vk_pipeline_layout
+            ? state->vk_pipeline_layout : root_signature->vk_pipeline_layout;
+    if (FAILED(hr = vkd3d_create_compute_pipeline(device, &desc->CS, &shader_interface,
+            vk_pipeline_layout, &state->u.compute.vk_pipeline)))
+    {
+        WARN("Failed to create Vulkan compute pipeline, hr %#x.\n", hr);
+        if (state->vk_set_layout)
+            VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout, NULL));
+        if (state->vk_pipeline_layout)
+            VK_CALL(vkDestroyPipelineLayout(device->vk_device, state->vk_pipeline_layout, NULL));
+        vkd3d_free(state->uav_counters);
+        return hr;
+    }
+
+    if (FAILED(hr = vkd3d_private_store_init(&state->private_store)))
+    {
+        VK_CALL(vkDestroyPipeline(device->vk_device, state->u.compute.vk_pipeline, NULL));
+        if (state->vk_set_layout)
+            VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout, NULL));
+        if (state->vk_pipeline_layout)
+            VK_CALL(vkDestroyPipelineLayout(device->vk_device, state->vk_pipeline_layout, NULL));
+        vkd3d_free(state->uav_counters);
+        return hr;
+    }
+
+    state->vk_bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
+    d3d12_device_add_ref(state->device = device);
+
+    return S_OK;
+}
+
+HRESULT d3d12_pipeline_state_create_compute(struct d3d12_device *device,
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state)
+{
+    struct d3d12_pipeline_state *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_pipeline_state_init_compute(object, device, desc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created compute pipeline state %p.\n", object);
+
+    *state = object;
+
+    return S_OK;
+}
+
+static enum VkPolygonMode vk_polygon_mode_from_d3d12(D3D12_FILL_MODE mode)
+{
+    switch (mode)
+    {
+        case D3D12_FILL_MODE_WIREFRAME:
+            return VK_POLYGON_MODE_LINE;
+        case D3D12_FILL_MODE_SOLID:
+            return VK_POLYGON_MODE_FILL;
+        default:
+            FIXME("Unhandled fill mode %#x.\n", mode);
+            return VK_POLYGON_MODE_FILL;
+    }
+}
+
+static enum VkCullModeFlagBits vk_cull_mode_from_d3d12(D3D12_CULL_MODE mode)
+{
+    switch (mode)
+    {
+        case D3D12_CULL_MODE_NONE:
+            return VK_CULL_MODE_NONE;
+        case D3D12_CULL_MODE_FRONT:
+            return VK_CULL_MODE_FRONT_BIT;
+        case D3D12_CULL_MODE_BACK:
+            return VK_CULL_MODE_BACK_BIT;
+        default:
+            FIXME("Unhandled cull mode %#x.\n", mode);
+            return VK_CULL_MODE_NONE;
+    }
+}
+
+static void rs_desc_from_d3d12(VkPipelineRasterizationStateCreateInfo *vk_desc,
+        const D3D12_RASTERIZER_DESC *d3d12_desc)
+{
+    vk_desc->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+    vk_desc->pNext = NULL;
+    vk_desc->flags = 0;
+    vk_desc->depthClampEnable = !d3d12_desc->DepthClipEnable;
+    vk_desc->rasterizerDiscardEnable = VK_FALSE;
+    vk_desc->polygonMode = vk_polygon_mode_from_d3d12(d3d12_desc->FillMode);
+    vk_desc->cullMode = vk_cull_mode_from_d3d12(d3d12_desc->CullMode);
+    vk_desc->frontFace = d3d12_desc->FrontCounterClockwise ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
+    vk_desc->depthBiasEnable = d3d12_desc->DepthBias || d3d12_desc->SlopeScaledDepthBias;
+    vk_desc->depthBiasConstantFactor = d3d12_desc->DepthBias;
+    vk_desc->depthBiasClamp = d3d12_desc->DepthBiasClamp;
+    vk_desc->depthBiasSlopeFactor = d3d12_desc->SlopeScaledDepthBias;
+    vk_desc->lineWidth = 1.0f;
+
+    if (d3d12_desc->MultisampleEnable)
+        FIXME_ONCE("Ignoring MultisampleEnable %#x.\n", d3d12_desc->MultisampleEnable);
+    if (d3d12_desc->AntialiasedLineEnable)
+        FIXME_ONCE("Ignoring AntialiasedLineEnable %#x.\n", d3d12_desc->AntialiasedLineEnable);
+    if (d3d12_desc->ForcedSampleCount)
+        FIXME("Ignoring ForcedSampleCount %#x.\n", d3d12_desc->ForcedSampleCount);
+    if (d3d12_desc->ConservativeRaster)
+        FIXME("Ignoring ConservativeRaster %#x.\n", d3d12_desc->ConservativeRaster);
+}
+
+static void rs_depth_clip_info_from_d3d12(VkPipelineRasterizationDepthClipStateCreateInfoEXT *depth_clip_info,
+        VkPipelineRasterizationStateCreateInfo *vk_rs_desc, const D3D12_RASTERIZER_DESC *d3d12_desc)
+{
+    vk_rs_desc->depthClampEnable = VK_TRUE;
+
+    depth_clip_info->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT;
+    depth_clip_info->pNext = NULL;
+    depth_clip_info->flags = 0;
+    depth_clip_info->depthClipEnable = d3d12_desc->DepthClipEnable;
+
+    vk_prepend_struct(vk_rs_desc, depth_clip_info);
+}
+
+static void rs_stream_info_from_d3d12(VkPipelineRasterizationStateStreamCreateInfoEXT *stream_info,
+        VkPipelineRasterizationStateCreateInfo *vk_rs_desc, const D3D12_STREAM_OUTPUT_DESC *so_desc,
+        const struct vkd3d_vulkan_info *vk_info)
+{
+    if (!so_desc->RasterizedStream || so_desc->RasterizedStream == D3D12_SO_NO_RASTERIZED_STREAM)
+        return;
+
+    if (!vk_info->rasterization_stream)
+    {
+        FIXME("Rasterization stream select is not supported by Vulkan implementation.\n");
+        return;
+    }
+
+    stream_info->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT;
+    stream_info->pNext = NULL;
+    stream_info->flags = 0;
+    stream_info->rasterizationStream = so_desc->RasterizedStream;
+
+    vk_prepend_struct(vk_rs_desc, stream_info);
+}
+
+static enum VkStencilOp vk_stencil_op_from_d3d12(D3D12_STENCIL_OP op)
+{
+    switch (op)
+    {
+        case D3D12_STENCIL_OP_KEEP:
+            return VK_STENCIL_OP_KEEP;
+        case D3D12_STENCIL_OP_ZERO:
+            return VK_STENCIL_OP_ZERO;
+        case D3D12_STENCIL_OP_REPLACE:
+            return VK_STENCIL_OP_REPLACE;
+        case D3D12_STENCIL_OP_INCR_SAT:
+            return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
+        case D3D12_STENCIL_OP_DECR_SAT:
+            return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
+        case D3D12_STENCIL_OP_INVERT:
+            return VK_STENCIL_OP_INVERT;
+        case D3D12_STENCIL_OP_INCR:
+            return VK_STENCIL_OP_INCREMENT_AND_WRAP;
+        case D3D12_STENCIL_OP_DECR:
+            return VK_STENCIL_OP_DECREMENT_AND_WRAP;
+        default:
+            FIXME("Unhandled stencil op %#x.\n", op);
+            return VK_STENCIL_OP_KEEP;
+    }
+}
+
+enum VkCompareOp vk_compare_op_from_d3d12(D3D12_COMPARISON_FUNC op)
+{
+    switch (op)
+    {
+        case D3D12_COMPARISON_FUNC_NEVER:
+            return VK_COMPARE_OP_NEVER;
+        case D3D12_COMPARISON_FUNC_LESS:
+            return VK_COMPARE_OP_LESS;
+        case D3D12_COMPARISON_FUNC_EQUAL:
+            return VK_COMPARE_OP_EQUAL;
+        case D3D12_COMPARISON_FUNC_LESS_EQUAL:
+            return VK_COMPARE_OP_LESS_OR_EQUAL;
+        case D3D12_COMPARISON_FUNC_GREATER:
+            return VK_COMPARE_OP_GREATER;
+        case D3D12_COMPARISON_FUNC_NOT_EQUAL:
+            return VK_COMPARE_OP_NOT_EQUAL;
+        case D3D12_COMPARISON_FUNC_GREATER_EQUAL:
+            return VK_COMPARE_OP_GREATER_OR_EQUAL;
+        case D3D12_COMPARISON_FUNC_ALWAYS:
+            return VK_COMPARE_OP_ALWAYS;
+        default:
+            FIXME("Unhandled compare op %#x.\n", op);
+            return VK_COMPARE_OP_NEVER;
+    }
+}
+
+static void vk_stencil_op_state_from_d3d12(struct VkStencilOpState *vk_desc,
+        const D3D12_DEPTH_STENCILOP_DESC *d3d12_desc, uint32_t compare_mask, uint32_t write_mask)
+{
+    vk_desc->failOp = vk_stencil_op_from_d3d12(d3d12_desc->StencilFailOp);
+    vk_desc->passOp = vk_stencil_op_from_d3d12(d3d12_desc->StencilPassOp);
+    vk_desc->depthFailOp = vk_stencil_op_from_d3d12(d3d12_desc->StencilDepthFailOp);
+    vk_desc->compareOp = vk_compare_op_from_d3d12(d3d12_desc->StencilFunc);
+    vk_desc->compareMask = compare_mask;
+    vk_desc->writeMask = write_mask;
+    /* The stencil reference value is a dynamic state. Set by OMSetStencilRef(). */
+    vk_desc->reference = 0;
+}
+
+static void ds_desc_from_d3d12(struct VkPipelineDepthStencilStateCreateInfo *vk_desc,
+        const D3D12_DEPTH_STENCIL_DESC *d3d12_desc)
+{
+    memset(vk_desc, 0, sizeof(*vk_desc));
+    vk_desc->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+    vk_desc->pNext = NULL;
+    vk_desc->flags = 0;
+    if ((vk_desc->depthTestEnable = d3d12_desc->DepthEnable))
+    {
+        vk_desc->depthWriteEnable = d3d12_desc->DepthWriteMask & D3D12_DEPTH_WRITE_MASK_ALL;
+        vk_desc->depthCompareOp = vk_compare_op_from_d3d12(d3d12_desc->DepthFunc);
+    }
+    else
+    {
+        vk_desc->depthWriteEnable = VK_FALSE;
+        vk_desc->depthCompareOp = VK_COMPARE_OP_NEVER;
+    }
+    vk_desc->depthBoundsTestEnable = VK_FALSE;
+    if ((vk_desc->stencilTestEnable = d3d12_desc->StencilEnable))
+    {
+        vk_stencil_op_state_from_d3d12(&vk_desc->front, &d3d12_desc->FrontFace,
+                d3d12_desc->StencilReadMask, d3d12_desc->StencilWriteMask);
+        vk_stencil_op_state_from_d3d12(&vk_desc->back, &d3d12_desc->BackFace,
+                d3d12_desc->StencilReadMask, d3d12_desc->StencilWriteMask);
+    }
+    else
+    {
+        memset(&vk_desc->front, 0, sizeof(vk_desc->front));
+        memset(&vk_desc->back, 0, sizeof(vk_desc->back));
+    }
+    vk_desc->minDepthBounds = 0.0f;
+    vk_desc->maxDepthBounds = 1.0f;
+}
+
+static enum VkBlendFactor vk_blend_factor_from_d3d12(D3D12_BLEND blend, bool alpha)
+{
+    switch (blend)
+    {
+        case D3D12_BLEND_ZERO:
+            return VK_BLEND_FACTOR_ZERO;
+        case D3D12_BLEND_ONE:
+            return VK_BLEND_FACTOR_ONE;
+        case D3D12_BLEND_SRC_COLOR:
+            return VK_BLEND_FACTOR_SRC_COLOR;
+        case D3D12_BLEND_INV_SRC_COLOR:
+            return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
+        case D3D12_BLEND_SRC_ALPHA:
+            return VK_BLEND_FACTOR_SRC_ALPHA;
+        case D3D12_BLEND_INV_SRC_ALPHA:
+            return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+        case D3D12_BLEND_DEST_ALPHA:
+            return VK_BLEND_FACTOR_DST_ALPHA;
+        case D3D12_BLEND_INV_DEST_ALPHA:
+            return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
+        case D3D12_BLEND_DEST_COLOR:
+            return VK_BLEND_FACTOR_DST_COLOR;
+        case D3D12_BLEND_INV_DEST_COLOR:
+            return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
+        case D3D12_BLEND_SRC_ALPHA_SAT:
+            return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
+        case D3D12_BLEND_BLEND_FACTOR:
+            if (alpha)
+                return VK_BLEND_FACTOR_CONSTANT_ALPHA;
+            return VK_BLEND_FACTOR_CONSTANT_COLOR;
+        case D3D12_BLEND_INV_BLEND_FACTOR:
+            if (alpha)
+                return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
+            return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
+        case D3D12_BLEND_SRC1_COLOR:
+            return VK_BLEND_FACTOR_SRC1_COLOR;
+        case D3D12_BLEND_INV_SRC1_COLOR:
+            return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
+        case D3D12_BLEND_SRC1_ALPHA:
+            return VK_BLEND_FACTOR_SRC1_ALPHA;
+        case D3D12_BLEND_INV_SRC1_ALPHA:
+            return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
+        default:
+            FIXME("Unhandled blend %#x.\n", blend);
+            return VK_BLEND_FACTOR_ZERO;
+    }
+}
+
+static enum VkBlendOp vk_blend_op_from_d3d12(D3D12_BLEND_OP op)
+{
+    switch (op)
+    {
+        case D3D12_BLEND_OP_ADD:
+            return VK_BLEND_OP_ADD;
+        case D3D12_BLEND_OP_SUBTRACT:
+            return VK_BLEND_OP_SUBTRACT;
+        case D3D12_BLEND_OP_REV_SUBTRACT:
+            return VK_BLEND_OP_REVERSE_SUBTRACT;
+        case D3D12_BLEND_OP_MIN:
+            return VK_BLEND_OP_MIN;
+        case D3D12_BLEND_OP_MAX:
+            return VK_BLEND_OP_MAX;
+        default:
+            FIXME("Unhandled blend op %#x.\n", op);
+            return VK_BLEND_OP_ADD;
+    }
+}
+
+static void blend_attachment_from_d3d12(struct VkPipelineColorBlendAttachmentState *vk_desc,
+        const D3D12_RENDER_TARGET_BLEND_DESC *d3d12_desc)
+{
+    if (d3d12_desc->BlendEnable)
+    {
+        vk_desc->blendEnable = VK_TRUE;
+        vk_desc->srcColorBlendFactor = vk_blend_factor_from_d3d12(d3d12_desc->SrcBlend, false);
+        vk_desc->dstColorBlendFactor = vk_blend_factor_from_d3d12(d3d12_desc->DestBlend, false);
+        vk_desc->colorBlendOp = vk_blend_op_from_d3d12(d3d12_desc->BlendOp);
+        vk_desc->srcAlphaBlendFactor = vk_blend_factor_from_d3d12(d3d12_desc->SrcBlendAlpha, true);
+        vk_desc->dstAlphaBlendFactor = vk_blend_factor_from_d3d12(d3d12_desc->DestBlendAlpha, true);
+        vk_desc->alphaBlendOp = vk_blend_op_from_d3d12(d3d12_desc->BlendOpAlpha);
+    }
+    else
+    {
+        memset(vk_desc, 0, sizeof(*vk_desc));
+    }
+    vk_desc->colorWriteMask = 0;
+    if (d3d12_desc->RenderTargetWriteMask & D3D12_COLOR_WRITE_ENABLE_RED)
+        vk_desc->colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
+    if (d3d12_desc->RenderTargetWriteMask & D3D12_COLOR_WRITE_ENABLE_GREEN)
+        vk_desc->colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
+    if (d3d12_desc->RenderTargetWriteMask & D3D12_COLOR_WRITE_ENABLE_BLUE)
+        vk_desc->colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
+    if (d3d12_desc->RenderTargetWriteMask & D3D12_COLOR_WRITE_ENABLE_ALPHA)
+        vk_desc->colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
+
+    if (d3d12_desc->LogicOpEnable)
+        FIXME("Ignoring LogicOpEnable %#x.\n", d3d12_desc->LogicOpEnable);
+}
+
+static bool is_dual_source_blending_blend(D3D12_BLEND b)
+{
+    return b == D3D12_BLEND_SRC1_COLOR || b == D3D12_BLEND_INV_SRC1_COLOR
+            || b == D3D12_BLEND_SRC1_ALPHA || b == D3D12_BLEND_INV_SRC1_ALPHA;
+}
+
+static bool is_dual_source_blending(const D3D12_RENDER_TARGET_BLEND_DESC *desc)
+{
+    return desc->BlendEnable
+            && (is_dual_source_blending_blend(desc->SrcBlend)
+            || is_dual_source_blending_blend(desc->DestBlend)
+            || is_dual_source_blending_blend(desc->SrcBlendAlpha)
+            || is_dual_source_blending_blend(desc->DestBlendAlpha));
+}
+
+static HRESULT compute_input_layout_offsets(const struct d3d12_device *device,
+        const D3D12_INPUT_LAYOUT_DESC *input_layout_desc, uint32_t *offsets)
+{
+    uint32_t input_slot_offsets[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = {0};
+    const D3D12_INPUT_ELEMENT_DESC *e;
+    const struct vkd3d_format *format;
+    unsigned int i;
+
+    if (input_layout_desc->NumElements > D3D12_VS_INPUT_REGISTER_COUNT)
+    {
+        FIXME("InputLayout.NumElements %u > %u, ignoring extra elements.\n",
+                input_layout_desc->NumElements, D3D12_VS_INPUT_REGISTER_COUNT);
+    }
+
+    for (i = 0; i < min(input_layout_desc->NumElements, D3D12_VS_INPUT_REGISTER_COUNT); ++i)
+    {
+        e = &input_layout_desc->pInputElementDescs[i];
+
+        if (e->InputSlot >= ARRAY_SIZE(input_slot_offsets))
+        {
+            WARN("Invalid input slot %#x.\n", e->InputSlot);
+            return E_INVALIDARG;
+        }
+
+        if (!(format = vkd3d_get_format(device, e->Format, false)))
+        {
+            WARN("Invalid input element format %#x.\n", e->Format);
+            return E_INVALIDARG;
+        }
+
+        if (e->AlignedByteOffset != D3D12_APPEND_ALIGNED_ELEMENT)
+            offsets[i] = e->AlignedByteOffset;
+        else
+            offsets[i] = input_slot_offsets[e->InputSlot];
+
+        input_slot_offsets[e->InputSlot] = align(offsets[i] + format->byte_count, 4);
+    }
+
+    return S_OK;
+}
+
+static unsigned int vkd3d_get_rt_format_swizzle(const struct vkd3d_format *format)
+{
+    if (format->dxgi_format == DXGI_FORMAT_A8_UNORM)
+        return VKD3D_SHADER_SWIZZLE(W, X, Y, Z);
+
+    return VKD3D_SHADER_NO_SWIZZLE;
+}
+
+STATIC_ASSERT(sizeof(struct vkd3d_shader_transform_feedback_element) == sizeof(D3D12_SO_DECLARATION_ENTRY));
+
+static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
+        struct d3d12_graphics_pipeline_state *graphics, struct d3d12_device *device,
+        VkFormat dynamic_dsv_format, VkRenderPass *vk_render_pass)
+{
+    struct vkd3d_render_pass_key key;
+    VkFormat dsv_format;
+    unsigned int i;
+
+    memcpy(key.vk_formats, graphics->rtv_formats, sizeof(graphics->rtv_formats));
+    key.attachment_count = graphics->rt_count;
+
+    if (!(dsv_format = graphics->dsv_format) && (graphics->null_attachment_mask & dsv_attachment_mask(graphics)))
+        dsv_format = dynamic_dsv_format;
+
+    if (dsv_format)
+    {
+        assert(graphics->ds_desc.front.writeMask == graphics->ds_desc.back.writeMask);
+        key.depth_enable = graphics->ds_desc.depthTestEnable;
+        key.stencil_enable = graphics->ds_desc.stencilTestEnable;
+        key.depth_stencil_write = graphics->ds_desc.depthWriteEnable
+                || graphics->ds_desc.front.writeMask;
+        key.vk_formats[key.attachment_count++] = dsv_format;
+    }
+    else
+    {
+        key.depth_enable = false;
+        key.stencil_enable = false;
+        key.depth_stencil_write = false;
+    }
+
+    if (key.attachment_count != ARRAY_SIZE(key.vk_formats))
+        key.vk_formats[ARRAY_SIZE(key.vk_formats) - 1] = VK_FORMAT_UNDEFINED;
+    for (i = key.attachment_count; i < ARRAY_SIZE(key.vk_formats); ++i)
+        assert(key.vk_formats[i] == VK_FORMAT_UNDEFINED);
+
+    key.padding = 0;
+    key.sample_count = graphics->ms_desc.rasterizationSamples;
+
+    return vkd3d_render_pass_cache_find(&device->render_pass_cache, device, &key, vk_render_pass);
+}
+
+static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *state,
+        struct d3d12_device *device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc)
+{
+    unsigned int ps_output_swizzle[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    const D3D12_STREAM_OUTPUT_DESC *so_desc = &desc->StreamOutput;
+    VkVertexInputBindingDivisorDescriptionEXT *binding_divisor;
+    const struct vkd3d_vulkan_info *vk_info = &device->vk_info;
+    uint32_t instance_divisors[D3D12_VS_INPUT_REGISTER_COUNT];
+    uint32_t aligned_offsets[D3D12_VS_INPUT_REGISTER_COUNT];
+    struct vkd3d_shader_parameter ps_shader_parameters[1];
+    struct vkd3d_shader_transform_feedback_info xfb_info;
+    struct vkd3d_shader_spirv_target_info ps_target_info;
+    struct vkd3d_shader_interface_info shader_interface;
+    struct vkd3d_shader_spirv_target_info *target_info;
+    const struct d3d12_root_signature *root_signature;
+    struct vkd3d_shader_signature input_signature;
+    bool have_attachment, is_dsv_format_unknown;
+    VkShaderStageFlagBits xfb_stage = 0;
+    VkSampleCountFlagBits sample_count;
+    const struct vkd3d_format *format;
+    unsigned int instance_divisor;
+    VkVertexInputRate input_rate;
+    unsigned int i, j;
+    size_t rt_count;
+    uint32_t mask;
+    HRESULT hr;
+    int ret;
+
+    static const DWORD default_ps_code[] =
+    {
+#if 0
+        ps_4_0
+        ret
+#endif
+        0x43425844, 0x19cbf606, 0x18f562b9, 0xdaeed4db, 0xc324aa46, 0x00000001, 0x00000060, 0x00000003,
+        0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+        0x00000008, 0x00000000, 0x00000008, 0x52444853, 0x0000000c, 0x00000040, 0x00000003, 0x0100003e,
+    };
+    static const D3D12_SHADER_BYTECODE default_ps = {default_ps_code, sizeof(default_ps_code)};
+    static const struct
+    {
+        enum VkShaderStageFlagBits stage;
+        ptrdiff_t offset;
+    }
+    shader_stages[] =
+    {
+        {VK_SHADER_STAGE_VERTEX_BIT,                  offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, VS)},
+        {VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, HS)},
+        {VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, DS)},
+        {VK_SHADER_STAGE_GEOMETRY_BIT,                offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, GS)},
+        {VK_SHADER_STAGE_FRAGMENT_BIT,                offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, PS)},
+    };
+
+    state->ID3D12PipelineState_iface.lpVtbl = &d3d12_pipeline_state_vtbl;
+    state->refcount = 1;
+
+    state->vk_pipeline_layout = VK_NULL_HANDLE;
+    state->vk_set_layout = VK_NULL_HANDLE;
+    state->uav_counters = NULL;
+    state->uav_counter_count = 0;
+    graphics->stage_count = 0;
+
+    memset(&input_signature, 0, sizeof(input_signature));
+
+    for (i = desc->NumRenderTargets; i < ARRAY_SIZE(desc->RTVFormats); ++i)
+    {
+        if (desc->RTVFormats[i] != DXGI_FORMAT_UNKNOWN)
+        {
+            WARN("Format must be set to DXGI_FORMAT_UNKNOWN for inactive render targets.\n");
+            return E_INVALIDARG;
+        }
+    }
+
+    if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->pRootSignature)))
+    {
+        WARN("Root signature is NULL.\n");
+        return E_INVALIDARG;
+    }
+
+    sample_count = vk_samples_from_dxgi_sample_desc(&desc->SampleDesc);
+    if (desc->SampleDesc.Count != 1 && desc->SampleDesc.Quality)
+        WARN("Ignoring sample quality %u.\n", desc->SampleDesc.Quality);
+
+    rt_count = desc->NumRenderTargets;
+    if (rt_count > ARRAY_SIZE(graphics->blend_attachments))
+    {
+        FIXME("NumRenderTargets %zu > %zu, ignoring extra formats.\n",
+                rt_count, ARRAY_SIZE(graphics->blend_attachments));
+        rt_count = ARRAY_SIZE(graphics->blend_attachments);
+    }
+
+    graphics->null_attachment_mask = 0;
+    for (i = 0; i < rt_count; ++i)
+    {
+        const D3D12_RENDER_TARGET_BLEND_DESC *rt_desc;
+
+        if (desc->RTVFormats[i] == DXGI_FORMAT_UNKNOWN)
+        {
+            graphics->null_attachment_mask |= 1u << i;
+            ps_output_swizzle[i] = VKD3D_SHADER_NO_SWIZZLE;
+            graphics->rtv_formats[i] = VK_FORMAT_UNDEFINED;
+        }
+        else if ((format = vkd3d_get_format(device, desc->RTVFormats[i], false)))
+        {
+            ps_output_swizzle[i] = vkd3d_get_rt_format_swizzle(format);
+            graphics->rtv_formats[i] = format->vk_format;
+        }
+        else
+        {
+            WARN("Invalid RTV format %#x.\n", desc->RTVFormats[i]);
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        rt_desc = &desc->BlendState.RenderTarget[desc->BlendState.IndependentBlendEnable ? i : 0];
+        if (desc->BlendState.IndependentBlendEnable && rt_desc->LogicOpEnable)
+        {
+            WARN("IndependentBlendEnable must be FALSE when logic operations are enabled.\n");
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+        if (rt_desc->BlendEnable && rt_desc->LogicOpEnable)
+        {
+            WARN("Only one of BlendEnable or LogicOpEnable can be set to TRUE.");
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        blend_attachment_from_d3d12(&graphics->blend_attachments[i], rt_desc);
+    }
+    for (i = rt_count; i < ARRAY_SIZE(graphics->rtv_formats); ++i)
+        graphics->rtv_formats[i] = VK_FORMAT_UNDEFINED;
+    graphics->rt_count = rt_count;
+
+    ds_desc_from_d3d12(&graphics->ds_desc, &desc->DepthStencilState);
+    if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN
+            && graphics->ds_desc.depthTestEnable && !graphics->ds_desc.depthWriteEnable
+            && graphics->ds_desc.depthCompareOp == VK_COMPARE_OP_ALWAYS && !graphics->ds_desc.stencilTestEnable)
+    {
+        TRACE("Disabling depth test.\n");
+        graphics->ds_desc.depthTestEnable = VK_FALSE;
+    }
+
+    graphics->dsv_format = VK_FORMAT_UNDEFINED;
+    if (graphics->ds_desc.depthTestEnable || graphics->ds_desc.stencilTestEnable)
+    {
+        if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN)
+        {
+            WARN("DSV format is DXGI_FORMAT_UNKNOWN.\n");
+            graphics->dsv_format = VK_FORMAT_UNDEFINED;
+            graphics->null_attachment_mask |= dsv_attachment_mask(graphics);
+        }
+        else if ((format = vkd3d_get_format(device, desc->DSVFormat, true)))
+        {
+            if (!(format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))
+                FIXME("Format %#x is not depth/stencil format.\n", format->dxgi_format);
+
+            graphics->dsv_format = format->vk_format;
+        }
+        else
+        {
+            WARN("Invalid DSV format %#x.\n", desc->DSVFormat);
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        if (!desc->PS.pShaderBytecode)
+        {
+            if (FAILED(hr = create_shader_stage(device, &graphics->stages[graphics->stage_count],
+                    VK_SHADER_STAGE_FRAGMENT_BIT, &default_ps, NULL)))
+                goto fail;
+
+            ++graphics->stage_count;
+        }
+    }
+
+    ps_shader_parameters[0].name = VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT;
+    ps_shader_parameters[0].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
+    ps_shader_parameters[0].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32;
+    ps_shader_parameters[0].u.immediate_constant.u.u32 = sample_count;
+
+    ps_target_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO;
+    ps_target_info.next = NULL;
+    ps_target_info.entry_point = "main";
+    ps_target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
+    ps_target_info.extensions = vk_info->shader_extensions;
+    ps_target_info.extension_count = vk_info->shader_extension_count;
+    ps_target_info.parameters = ps_shader_parameters;
+    ps_target_info.parameter_count = ARRAY_SIZE(ps_shader_parameters);
+    ps_target_info.dual_source_blending = is_dual_source_blending(&desc->BlendState.RenderTarget[0]);
+    ps_target_info.output_swizzles = ps_output_swizzle;
+    ps_target_info.output_swizzle_count = rt_count;
+
+    if (ps_target_info.dual_source_blending && rt_count > 1)
+    {
+        WARN("Only one render target is allowed when dual source blending is used.\n");
+        hr = E_INVALIDARG;
+        goto fail;
+    }
+    if (ps_target_info.dual_source_blending && desc->BlendState.IndependentBlendEnable)
+    {
+        for (i = 1; i < ARRAY_SIZE(desc->BlendState.RenderTarget); ++i)
+        {
+            if (desc->BlendState.RenderTarget[i].BlendEnable)
+            {
+                WARN("Blend enable cannot be set for render target %u when dual source blending is used.\n", i);
+                hr = E_INVALIDARG;
+                goto fail;
+            }
+        }
+    }
+
+    graphics->xfb_enabled = false;
+    if (so_desc->NumEntries)
+    {
+        if (!(root_signature->flags & D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT))
+        {
+            WARN("Stream output is used without D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT.\n");
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        if (!vk_info->EXT_transform_feedback)
+        {
+            FIXME("Transform feedback is not supported by Vulkan implementation.\n");
+            hr = E_NOTIMPL;
+            goto fail;
+        }
+
+        graphics->xfb_enabled = true;
+
+        xfb_info.type = VKD3D_SHADER_STRUCTURE_TYPE_TRANSFORM_FEEDBACK_INFO;
+        xfb_info.next = NULL;
+
+        xfb_info.elements = (const struct vkd3d_shader_transform_feedback_element *)so_desc->pSODeclaration;
+        xfb_info.element_count = so_desc->NumEntries;
+        xfb_info.buffer_strides = so_desc->pBufferStrides;
+        xfb_info.buffer_stride_count = so_desc->NumStrides;
+
+        if (desc->GS.pShaderBytecode)
+            xfb_stage = VK_SHADER_STAGE_GEOMETRY_BIT;
+        else if (desc->DS.pShaderBytecode)
+            xfb_stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+        else
+            xfb_stage = VK_SHADER_STAGE_VERTEX_BIT;
+    }
+
+    shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO;
+    shader_interface.next = NULL;
+    shader_interface.bindings = root_signature->descriptor_mapping;
+    shader_interface.binding_count = root_signature->descriptor_count;
+    shader_interface.push_constant_buffers = root_signature->root_constants;
+    shader_interface.push_constant_buffer_count = root_signature->root_constant_count;
+    shader_interface.combined_samplers = NULL;
+    shader_interface.combined_sampler_count = 0;
+    shader_interface.uav_counters = NULL;
+    shader_interface.uav_counter_count = 0;
+
+    for (i = 0; i < ARRAY_SIZE(shader_stages); ++i)
+    {
+        struct vkd3d_shader_scan_descriptor_info shader_info =
+        {
+            .type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO,
+        };
+        const D3D12_SHADER_BYTECODE *b = (const void *)((uintptr_t)desc + shader_stages[i].offset);
+        const struct vkd3d_shader_code dxbc = {b->pShaderBytecode, b->BytecodeLength};
+
+        if (!b->pShaderBytecode)
+            continue;
+
+        if ((ret = vkd3d_scan_dxbc(b, &shader_info)) < 0)
+        {
+            WARN("Failed to scan shader bytecode, stage %#x, vkd3d result %d.\n",
+                    shader_stages[i].stage, ret);
+            hr = hresult_from_vkd3d_result(ret);
+            goto fail;
+        }
+        for (j = 0; j < shader_info.descriptor_count; ++j)
+        {
+            const struct vkd3d_shader_descriptor_info *d = &shader_info.descriptors[j];
+
+            if (d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV
+                    && (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER))
+            {
+                FIXME("UAV counters not implemented for graphics pipelines.\n");
+                break;
+            }
+        }
+        vkd3d_shader_free_scan_descriptor_info(&shader_info);
+
+        target_info = NULL;
+        switch (shader_stages[i].stage)
+        {
+            case VK_SHADER_STAGE_VERTEX_BIT:
+                if ((ret = vkd3d_shader_parse_input_signature(&dxbc, &input_signature, NULL)) < 0)
+                {
+                    hr = hresult_from_vkd3d_result(ret);
+                    goto fail;
+                }
+                break;
+
+            case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
+            case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
+                if (desc->PrimitiveTopologyType != D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH)
+                {
+                    WARN("D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH must be used with tessellation shaders.\n");
+                    hr = E_INVALIDARG;
+                    goto fail;
+                }
+                break;
+
+            case VK_SHADER_STAGE_GEOMETRY_BIT:
+                break;
+
+            case VK_SHADER_STAGE_FRAGMENT_BIT:
+                target_info = &ps_target_info;
+                break;
+
+            default:
+                hr = E_INVALIDARG;
+                goto fail;
+        }
+
+        shader_interface.next = shader_stages[i].stage == xfb_stage ? &xfb_info : NULL;
+        if (target_info)
+        {
+            target_info->next = shader_interface.next;
+            shader_interface.next = target_info;
+        }
+
+        if (FAILED(hr = create_shader_stage(device, &graphics->stages[graphics->stage_count],
+                shader_stages[i].stage, b, &shader_interface)))
+            goto fail;
+
+        ++graphics->stage_count;
+    }
+
+    graphics->attribute_count = desc->InputLayout.NumElements;
+    if (graphics->attribute_count > ARRAY_SIZE(graphics->attributes))
+    {
+        FIXME("InputLayout.NumElements %zu > %zu, ignoring extra elements.\n",
+                graphics->attribute_count, ARRAY_SIZE(graphics->attributes));
+        graphics->attribute_count = ARRAY_SIZE(graphics->attributes);
+    }
+
+    if (graphics->attribute_count
+            && !(root_signature->flags & D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT))
+    {
+        WARN("Input layout is used without D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT.\n");
+        hr = E_INVALIDARG;
+        goto fail;
+    }
+
+    if (FAILED(hr = compute_input_layout_offsets(device, &desc->InputLayout, aligned_offsets)))
+        goto fail;
+
+    graphics->instance_divisor_count = 0;
+    for (i = 0, j = 0, mask = 0; i < graphics->attribute_count; ++i)
+    {
+        const D3D12_INPUT_ELEMENT_DESC *e = &desc->InputLayout.pInputElementDescs[i];
+        const struct vkd3d_shader_signature_element *signature_element;
+
+        if (!(format = vkd3d_get_format(device, e->Format, false)))
+        {
+            WARN("Invalid input element format %#x.\n", e->Format);
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        if (e->InputSlot >= ARRAY_SIZE(graphics->input_rates)
+                || e->InputSlot >= ARRAY_SIZE(instance_divisors))
+        {
+            WARN("Invalid input slot %#x.\n", e->InputSlot);
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        if (!(signature_element = vkd3d_shader_find_signature_element(&input_signature,
+                e->SemanticName, e->SemanticIndex, 0)))
+        {
+            WARN("Unused input element %u.\n", i);
+            continue;
+        }
+
+        graphics->attributes[j].location = signature_element->register_index;
+        graphics->attributes[j].binding = e->InputSlot;
+        graphics->attributes[j].format = format->vk_format;
+        if (e->AlignedByteOffset != D3D12_APPEND_ALIGNED_ELEMENT)
+            graphics->attributes[j].offset = e->AlignedByteOffset;
+        else
+            graphics->attributes[j].offset = aligned_offsets[i];
+        ++j;
+
+        switch (e->InputSlotClass)
+        {
+            case D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA:
+                input_rate = VK_VERTEX_INPUT_RATE_VERTEX;
+                instance_divisor = 1;
+                break;
+
+            case D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA:
+                input_rate = VK_VERTEX_INPUT_RATE_INSTANCE;
+                instance_divisor = e->InstanceDataStepRate;
+                if (instance_divisor > vk_info->max_vertex_attrib_divisor
+                        || (!instance_divisor && !vk_info->vertex_attrib_zero_divisor))
+                {
+                    FIXME("Instance divisor %u not supported by Vulkan implementation.\n", instance_divisor);
+                    instance_divisor = 1;
+                }
+                break;
+
+            default:
+                FIXME("Unhandled input slot class %#x on input element %u.\n", e->InputSlotClass, i);
+                hr = E_INVALIDARG;
+                goto fail;
+        }
+
+        if (mask & (1u << e->InputSlot) && (graphics->input_rates[e->InputSlot] != input_rate
+                || instance_divisors[e->InputSlot] != instance_divisor))
+        {
+            FIXME("Input slot rate %#x, instance divisor %u on input element %u conflicts "
+                    "with earlier input slot rate %#x, instance divisor %u.\n",
+                    input_rate, instance_divisor, e->InputSlot,
+                    graphics->input_rates[e->InputSlot], instance_divisors[e->InputSlot]);
+            hr = E_INVALIDARG;
+            goto fail;
+        }
+
+        graphics->input_rates[e->InputSlot] = input_rate;
+        instance_divisors[e->InputSlot] = instance_divisor;
+        if (instance_divisor != 1 && !(mask & (1u << e->InputSlot)))
+        {
+            binding_divisor = &graphics->instance_divisors[graphics->instance_divisor_count++];
+            binding_divisor->binding = e->InputSlot;
+            binding_divisor->divisor = instance_divisor;
+        }
+        mask |= 1u << e->InputSlot;
+    }
+    graphics->attribute_count = j;
+    vkd3d_shader_free_shader_signature(&input_signature);
+
+    switch (desc->IBStripCutValue)
+    {
+        case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED:
+        case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF:
+        case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF:
+            graphics->index_buffer_strip_cut_value = desc->IBStripCutValue;
+            break;
+        default:
+            WARN("Invalid index buffer strip cut value %#x.\n", desc->IBStripCutValue);
+            hr = E_INVALIDARG;
+            goto fail;
+    }
+
+    is_dsv_format_unknown = graphics->null_attachment_mask & dsv_attachment_mask(graphics);
+
+    rs_desc_from_d3d12(&graphics->rs_desc, &desc->RasterizerState);
+    have_attachment = graphics->rt_count || graphics->dsv_format || is_dsv_format_unknown;
+    if ((!have_attachment && !(desc->PS.pShaderBytecode && desc->PS.BytecodeLength))
+            || so_desc->RasterizedStream == D3D12_SO_NO_RASTERIZED_STREAM)
+        graphics->rs_desc.rasterizerDiscardEnable = VK_TRUE;
+
+    rs_stream_info_from_d3d12(&graphics->rs_stream_info, &graphics->rs_desc, so_desc, vk_info);
+    if (vk_info->EXT_depth_clip_enable)
+        rs_depth_clip_info_from_d3d12(&graphics->rs_depth_clip_info, &graphics->rs_desc, &desc->RasterizerState);
+
+    graphics->ms_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    graphics->ms_desc.pNext = NULL;
+    graphics->ms_desc.flags = 0;
+    graphics->ms_desc.rasterizationSamples = sample_count;
+    graphics->ms_desc.sampleShadingEnable = VK_FALSE;
+    graphics->ms_desc.minSampleShading = 0.0f;
+    graphics->ms_desc.pSampleMask = NULL;
+    if (desc->SampleMask != ~0u)
+    {
+        assert(DIV_ROUND_UP(sample_count, 32) <= ARRAY_SIZE(graphics->sample_mask));
+        graphics->sample_mask[0] = desc->SampleMask;
+        graphics->sample_mask[1] = 0xffffffffu;
+        graphics->ms_desc.pSampleMask = graphics->sample_mask;
+    }
+    graphics->ms_desc.alphaToCoverageEnable = desc->BlendState.AlphaToCoverageEnable;
+    graphics->ms_desc.alphaToOneEnable = VK_FALSE;
+
+    /* We defer creating the render pass for pipelines wth DSVFormat equal to
+     * DXGI_FORMAT_UNKNOWN. We take the actual DSV format from the bound DSV. */
+    if (is_dsv_format_unknown)
+        graphics->render_pass = VK_NULL_HANDLE;
+    else if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics,
+            device, 0, &graphics->render_pass)))
+        goto fail;
+
+    graphics->root_signature = root_signature;
+
+    list_init(&graphics->compiled_pipelines);
+
+    if (FAILED(hr = vkd3d_private_store_init(&state->private_store)))
+        goto fail;
+
+    state->vk_bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    d3d12_device_add_ref(state->device = device);
+
+    return S_OK;
+
+fail:
+    for (i = 0; i < graphics->stage_count; ++i)
+    {
+        VK_CALL(vkDestroyShaderModule(device->vk_device, state->u.graphics.stages[i].module, NULL));
+    }
+    vkd3d_shader_free_shader_signature(&input_signature);
+
+    return hr;
+}
+
+HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device,
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state)
+{
+    struct d3d12_pipeline_state *object;
+    HRESULT hr;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_pipeline_state_init_graphics(object, device, desc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    TRACE("Created graphics pipeline state %p.\n", object);
+
+    *state = object;
+
+    return S_OK;
+}
+
+static enum VkPrimitiveTopology vk_topology_from_d3d12_topology(D3D12_PRIMITIVE_TOPOLOGY topology)
+{
+    switch (topology)
+    {
+        case D3D_PRIMITIVE_TOPOLOGY_POINTLIST:
+            return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+        case D3D_PRIMITIVE_TOPOLOGY_LINELIST:
+            return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+        case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP:
+            return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
+        case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
+            return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+        case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
+            return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+        case D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST:
+        case D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST:
+            return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+        default:
+            FIXME("Unhandled primitive topology %#x.\n", topology);
+            return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+    }
+}
+
+static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12_pipeline_state *state,
+        const struct vkd3d_pipeline_key *key, VkRenderPass *vk_render_pass)
+{
+    const struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+    struct d3d12_device *device = state->device;
+    VkPipeline vk_pipeline = VK_NULL_HANDLE;
+    struct vkd3d_compiled_pipeline *current;
+    int rc;
+
+    *vk_render_pass = VK_NULL_HANDLE;
+
+    if (!(rc = pthread_mutex_lock(&device->mutex)))
+    {
+        LIST_FOR_EACH_ENTRY(current, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
+        {
+            if (!memcmp(&current->key, key, sizeof(*key)))
+            {
+                vk_pipeline = current->vk_pipeline;
+                *vk_render_pass = current->vk_render_pass;
+                break;
+            }
+        }
+        pthread_mutex_unlock(&device->mutex);
+    }
+    else
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+    }
+
+    return vk_pipeline;
+}
+
+static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_state *state,
+        const struct vkd3d_pipeline_key *key, VkPipeline vk_pipeline, VkRenderPass vk_render_pass)
+{
+    struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+    struct vkd3d_compiled_pipeline *compiled_pipeline, *current;
+    struct d3d12_device *device = state->device;
+    int rc;
+
+    if (!(compiled_pipeline = vkd3d_malloc(sizeof(*compiled_pipeline))))
+        return false;
+
+    compiled_pipeline->key = *key;
+    compiled_pipeline->vk_pipeline = vk_pipeline;
+    compiled_pipeline->vk_render_pass = vk_render_pass;
+
+    if ((rc = pthread_mutex_lock(&device->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        vkd3d_free(compiled_pipeline);
+        return false;
+    }
+
+    LIST_FOR_EACH_ENTRY(current, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
+    {
+        if (!memcmp(&current->key, key, sizeof(*key)))
+        {
+            vkd3d_free(compiled_pipeline);
+            compiled_pipeline = NULL;
+            break;
+        }
+    }
+
+    if (compiled_pipeline)
+        list_add_tail(&graphics->compiled_pipelines, &compiled_pipeline->entry);
+
+    pthread_mutex_unlock(&device->mutex);
+    return compiled_pipeline;
+}
+
+VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
+        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides, VkFormat dsv_format,
+        VkRenderPass *vk_render_pass)
+{
+    VkVertexInputBindingDescription bindings[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    const struct vkd3d_vk_device_procs *vk_procs = &state->device->vk_procs;
+    struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+    VkPipelineVertexInputDivisorStateCreateInfoEXT input_divisor_info;
+    VkPipelineTessellationStateCreateInfo tessellation_info;
+    VkPipelineVertexInputStateCreateInfo input_desc;
+    VkPipelineInputAssemblyStateCreateInfo ia_desc;
+    VkPipelineColorBlendStateCreateInfo blend_desc;
+    struct d3d12_device *device = state->device;
+    VkGraphicsPipelineCreateInfo pipeline_desc;
+    struct vkd3d_pipeline_key pipeline_key;
+    size_t binding_count = 0;
+    VkPipeline vk_pipeline;
+    unsigned int i;
+    uint32_t mask;
+    VkResult vr;
+    HRESULT hr;
+
+    static const VkPipelineViewportStateCreateInfo vp_desc =
+    {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+        .pNext = NULL,
+        .flags = 0,
+        .viewportCount = 1,
+        .pViewports = NULL,
+        .scissorCount = 1,
+        .pScissors = NULL,
+    };
+    static const VkDynamicState dynamic_states[] =
+    {
+        VK_DYNAMIC_STATE_VIEWPORT,
+        VK_DYNAMIC_STATE_SCISSOR,
+        VK_DYNAMIC_STATE_BLEND_CONSTANTS,
+        VK_DYNAMIC_STATE_STENCIL_REFERENCE,
+    };
+    static const VkPipelineDynamicStateCreateInfo dynamic_desc =
+    {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+        .pNext = NULL,
+        .flags = 0,
+        .dynamicStateCount = ARRAY_SIZE(dynamic_states),
+        .pDynamicStates = dynamic_states,
+    };
+
+    assert(d3d12_pipeline_state_is_graphics(state));
+
+    memset(&pipeline_key, 0, sizeof(pipeline_key));
+    pipeline_key.topology = topology;
+
+    for (i = 0, mask = 0; i < graphics->attribute_count; ++i)
+    {
+        struct VkVertexInputBindingDescription *b;
+        uint32_t binding;
+
+        binding = graphics->attributes[i].binding;
+        if (mask & (1u << binding))
+            continue;
+
+        if (binding_count == ARRAY_SIZE(bindings))
+        {
+            FIXME("Maximum binding count exceeded.\n");
+            break;
+        }
+
+        mask |= 1u << binding;
+        b = &bindings[binding_count];
+        b->binding = binding;
+        b->stride = strides[binding];
+        b->inputRate = graphics->input_rates[binding];
+
+        pipeline_key.strides[binding_count] = strides[binding];
+
+        ++binding_count;
+    }
+
+    pipeline_key.dsv_format = dsv_format;
+
+    if ((vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key, vk_render_pass)))
+        return vk_pipeline;
+
+    input_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+    input_desc.pNext = NULL;
+    input_desc.flags = 0;
+    input_desc.vertexBindingDescriptionCount = binding_count;
+    input_desc.pVertexBindingDescriptions = bindings;
+    input_desc.vertexAttributeDescriptionCount = graphics->attribute_count;
+    input_desc.pVertexAttributeDescriptions = graphics->attributes;
+
+    if (graphics->instance_divisor_count)
+    {
+        input_desc.pNext = &input_divisor_info;
+        input_divisor_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
+        input_divisor_info.pNext = NULL;
+        input_divisor_info.vertexBindingDivisorCount = graphics->instance_divisor_count;
+        input_divisor_info.pVertexBindingDivisors = graphics->instance_divisors;
+    }
+
+    ia_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    ia_desc.pNext = NULL;
+    ia_desc.flags = 0;
+    ia_desc.topology = vk_topology_from_d3d12_topology(topology);
+    ia_desc.primitiveRestartEnable = !!graphics->index_buffer_strip_cut_value;
+
+    tessellation_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+    tessellation_info.pNext = NULL;
+    tessellation_info.flags = 0;
+    tessellation_info.patchControlPoints
+            = max(topology - D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1, 1);
+
+    blend_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+    blend_desc.pNext = NULL;
+    blend_desc.flags = 0;
+    blend_desc.logicOpEnable = VK_FALSE;
+    blend_desc.logicOp = VK_LOGIC_OP_COPY;
+    blend_desc.attachmentCount = graphics->rt_count;
+    blend_desc.pAttachments = graphics->blend_attachments;
+    blend_desc.blendConstants[0] = D3D12_DEFAULT_BLEND_FACTOR_RED;
+    blend_desc.blendConstants[1] = D3D12_DEFAULT_BLEND_FACTOR_GREEN;
+    blend_desc.blendConstants[2] = D3D12_DEFAULT_BLEND_FACTOR_BLUE;
+    blend_desc.blendConstants[3] = D3D12_DEFAULT_BLEND_FACTOR_ALPHA;
+
+    pipeline_desc.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+    pipeline_desc.pNext = NULL;
+    pipeline_desc.flags = 0;
+    pipeline_desc.stageCount = graphics->stage_count;
+    pipeline_desc.pStages = graphics->stages;
+    pipeline_desc.pVertexInputState = &input_desc;
+    pipeline_desc.pInputAssemblyState = &ia_desc;
+    pipeline_desc.pTessellationState = &tessellation_info;
+    pipeline_desc.pViewportState = &vp_desc;
+    pipeline_desc.pRasterizationState = &graphics->rs_desc;
+    pipeline_desc.pMultisampleState = &graphics->ms_desc;
+    pipeline_desc.pDepthStencilState = &graphics->ds_desc;
+    pipeline_desc.pColorBlendState = &blend_desc;
+    pipeline_desc.pDynamicState = &dynamic_desc;
+    pipeline_desc.layout = graphics->root_signature->vk_pipeline_layout;
+    pipeline_desc.subpass = 0;
+    pipeline_desc.basePipelineHandle = VK_NULL_HANDLE;
+    pipeline_desc.basePipelineIndex = -1;
+
+    /* Create a render pass for pipelines with DXGI_FORMAT_UNKNOWN. */
+    if (!(pipeline_desc.renderPass = graphics->render_pass))
+    {
+        if (graphics->null_attachment_mask & dsv_attachment_mask(graphics))
+            TRACE("Compiling %p with DSV format %#x.\n", state, dsv_format);
+
+        if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics, device, dsv_format,
+                &pipeline_desc.renderPass)))
+            return VK_NULL_HANDLE;
+    }
+
+    *vk_render_pass = pipeline_desc.renderPass;
+
+    if ((vr = VK_CALL(vkCreateGraphicsPipelines(device->vk_device, device->vk_pipeline_cache,
+            1, &pipeline_desc, NULL, &vk_pipeline))) < 0)
+    {
+        WARN("Failed to create Vulkan graphics pipeline, vr %d.\n", vr);
+        return VK_NULL_HANDLE;
+    }
+
+    if (d3d12_pipeline_state_put_pipeline_to_cache(state, &pipeline_key, vk_pipeline, pipeline_desc.renderPass))
+        return vk_pipeline;
+
+    /* Other thread compiled the pipeline before us. */
+    VK_CALL(vkDestroyPipeline(device->vk_device, vk_pipeline, NULL));
+    vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key, vk_render_pass);
+    if (!vk_pipeline)
+        ERR("Could not get the pipeline compiled by other thread from the cache.\n");
+    return vk_pipeline;
+}
+
+static void vkd3d_uav_clear_pipelines_cleanup(struct vkd3d_uav_clear_pipelines *pipelines,
+        struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->image_3d, NULL));
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->image_2d_array, NULL));
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->image_2d, NULL));
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->image_1d_array, NULL));
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->image_1d, NULL));
+    VK_CALL(vkDestroyPipeline(device->vk_device, pipelines->buffer, NULL));
+}
+
+void vkd3d_uav_clear_state_cleanup(struct vkd3d_uav_clear_state *state, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+    vkd3d_uav_clear_pipelines_cleanup(&state->pipelines_uint, device);
+    vkd3d_uav_clear_pipelines_cleanup(&state->pipelines_float, device);
+
+    VK_CALL(vkDestroyPipelineLayout(device->vk_device, state->vk_pipeline_layout_image, NULL));
+    VK_CALL(vkDestroyPipelineLayout(device->vk_device, state->vk_pipeline_layout_buffer, NULL));
+
+    VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout_image, NULL));
+    VK_CALL(vkDestroyDescriptorSetLayout(device->vk_device, state->vk_set_layout_buffer, NULL));
+}
+
+HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d3d12_device *device)
+{
+    struct vkd3d_shader_push_constant_buffer push_constant;
+    struct vkd3d_shader_interface_info shader_interface;
+    struct vkd3d_shader_resource_binding binding;
+    VkDescriptorSetLayoutBinding set_binding;
+    VkPushConstantRange push_constant_range;
+    unsigned int i;
+    HRESULT hr;
+
+    const struct
+    {
+        VkDescriptorSetLayout *set_layout;
+        VkPipelineLayout *pipeline_layout;
+        VkDescriptorType descriptor_type;
+    }
+    set_layouts[] =
+    {
+        {&state->vk_set_layout_buffer, &state->vk_pipeline_layout_buffer, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER},
+        {&state->vk_set_layout_image,  &state->vk_pipeline_layout_image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE},
+    };
+
+    const struct
+    {
+        VkPipeline *pipeline;
+        VkPipelineLayout *pipeline_layout;
+        D3D12_SHADER_BYTECODE code;
+    }
+    pipelines[] =
+    {
+#define SHADER_CODE(name) {name, sizeof(name)}
+        {&state->pipelines_float.buffer, &state->vk_pipeline_layout_buffer,
+                SHADER_CODE(cs_uav_clear_buffer_float_code)},
+        {&state->pipelines_float.image_1d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_1d_float_code)},
+        {&state->pipelines_float.image_1d_array, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_1d_array_float_code)},
+        {&state->pipelines_float.image_2d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_2d_float_code)},
+        {&state->pipelines_float.image_2d_array, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_2d_array_float_code)},
+        {&state->pipelines_float.image_3d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_3d_float_code)},
+
+        {&state->pipelines_uint.buffer, &state->vk_pipeline_layout_buffer,
+                SHADER_CODE(cs_uav_clear_buffer_uint_code)},
+        {&state->pipelines_uint.image_1d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_1d_uint_code)},
+        {&state->pipelines_uint.image_1d_array, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_1d_array_uint_code)},
+        {&state->pipelines_uint.image_2d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_2d_uint_code)},
+        {&state->pipelines_uint.image_2d_array, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_2d_array_uint_code)},
+        {&state->pipelines_uint.image_3d, &state->vk_pipeline_layout_image,
+                SHADER_CODE(cs_uav_clear_3d_uint_code)},
+#undef SHADER_CODE
+    };
+
+    memset(state, 0, sizeof(*state));
+
+    set_binding.binding = 0;
+    set_binding.descriptorCount = 1;
+    set_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+    set_binding.pImmutableSamplers = NULL;
+
+    binding.type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+    binding.register_space = 0;
+    binding.register_index = 0;
+    binding.shader_visibility = VKD3D_SHADER_VISIBILITY_COMPUTE;
+    binding.binding.set = 0;
+    binding.binding.binding = 0;
+    binding.binding.count = 1;
+
+    push_constant_range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+    push_constant_range.offset = 0;
+    push_constant_range.size = sizeof(struct vkd3d_uav_clear_args);
+
+    push_constant.register_space = 0;
+    push_constant.register_index = 0;
+    push_constant.shader_visibility = VKD3D_SHADER_VISIBILITY_COMPUTE;
+    push_constant.offset = 0;
+    push_constant.size = sizeof(struct vkd3d_uav_clear_args);
+
+    for (i = 0; i < ARRAY_SIZE(set_layouts); ++i)
+    {
+        set_binding.descriptorType = set_layouts[i].descriptor_type;
+
+        if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, &set_binding, set_layouts[i].set_layout)))
+        {
+            ERR("Failed to create descriptor set layout %u, hr %#x.\n", i, hr);
+            goto fail;
+        }
+
+        if (FAILED(hr = vkd3d_create_pipeline_layout(device, 1, set_layouts[i].set_layout,
+                1, &push_constant_range, set_layouts[i].pipeline_layout)))
+        {
+            ERR("Failed to create pipeline layout %u, hr %#x.\n", i, hr);
+            goto fail;
+        }
+    }
+
+    shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO;
+    shader_interface.next = NULL;
+    shader_interface.bindings = &binding;
+    shader_interface.binding_count = 1;
+    shader_interface.push_constant_buffers = &push_constant;
+    shader_interface.push_constant_buffer_count = 1;
+    shader_interface.combined_samplers = NULL;
+    shader_interface.combined_sampler_count = 0;
+    shader_interface.uav_counters = NULL;
+    shader_interface.uav_counter_count = 0;
+
+    for (i = 0; i < ARRAY_SIZE(pipelines); ++i)
+    {
+        if (pipelines[i].pipeline_layout == &state->vk_pipeline_layout_buffer)
+            binding.flags = VKD3D_SHADER_BINDING_FLAG_BUFFER;
+        else
+            binding.flags = VKD3D_SHADER_BINDING_FLAG_IMAGE;
+
+        if (FAILED(hr = vkd3d_create_compute_pipeline(device, &pipelines[i].code, &shader_interface,
+                *pipelines[i].pipeline_layout, pipelines[i].pipeline)))
+        {
+            ERR("Failed to create compute pipeline %u, hr %#x.\n", i, hr);
+            goto fail;
+        }
+    }
+
+    return S_OK;
+
+fail:
+    vkd3d_uav_clear_state_cleanup(state, device);
+    return hr;
+}
diff --git a/dlls/vkd3d/libs/vkd3d/utils.c b/dlls/vkd3d/libs/vkd3d/utils.c
new file mode 100644
index 00000000000..f9f26635892
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/utils.c
@@ -0,0 +1,1080 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "vkd3d_private.h"
+
+#include <errno.h>
+
+#define COLOR         (VK_IMAGE_ASPECT_COLOR_BIT)
+#define DEPTH         (VK_IMAGE_ASPECT_DEPTH_BIT)
+#define STENCIL       (VK_IMAGE_ASPECT_STENCIL_BIT)
+#define DEPTH_STENCIL (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)
+#define TYPELESS      VKD3D_FORMAT_TYPE_TYPELESS
+#define SINT          VKD3D_FORMAT_TYPE_SINT
+#define UINT          VKD3D_FORMAT_TYPE_UINT
+static const struct vkd3d_format vkd3d_formats[] =
+{
+    {DXGI_FORMAT_R32G32B32A32_TYPELESS, VK_FORMAT_R32G32B32A32_SFLOAT,      16, 1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R32G32B32A32_FLOAT,    VK_FORMAT_R32G32B32A32_SFLOAT,      16, 1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R32G32B32A32_UINT,     VK_FORMAT_R32G32B32A32_UINT,        16, 1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R32G32B32A32_SINT,     VK_FORMAT_R32G32B32A32_SINT,        16, 1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R32G32B32_TYPELESS,    VK_FORMAT_R32G32B32_SFLOAT,         12, 1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R32G32B32_FLOAT,       VK_FORMAT_R32G32B32_SFLOAT,         12, 1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R32G32B32_UINT,        VK_FORMAT_R32G32B32_UINT,           12, 1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R32G32B32_SINT,        VK_FORMAT_R32G32B32_SINT,           12, 1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R16G16B16A16_TYPELESS, VK_FORMAT_R16G16B16A16_SFLOAT,      8,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R16G16B16A16_FLOAT,    VK_FORMAT_R16G16B16A16_SFLOAT,      8,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16B16A16_UNORM,    VK_FORMAT_R16G16B16A16_UNORM,       8,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16B16A16_UINT,     VK_FORMAT_R16G16B16A16_UINT,        8,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R16G16B16A16_SNORM,    VK_FORMAT_R16G16B16A16_SNORM,       8,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16B16A16_SINT,     VK_FORMAT_R16G16B16A16_SINT,        8,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R32G32_TYPELESS,       VK_FORMAT_R32G32_SFLOAT,            8,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R32G32_FLOAT,          VK_FORMAT_R32G32_SFLOAT,            8,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R32G32_UINT,           VK_FORMAT_R32G32_UINT,              8,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R32G32_SINT,           VK_FORMAT_R32G32_SINT,              8,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R10G10B10A2_TYPELESS,  VK_FORMAT_A2B10G10R10_UNORM_PACK32, 4,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R10G10B10A2_UNORM,     VK_FORMAT_A2B10G10R10_UNORM_PACK32, 4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R10G10B10A2_UINT,      VK_FORMAT_A2B10G10R10_UINT_PACK32,  4,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R11G11B10_FLOAT,       VK_FORMAT_B10G11R11_UFLOAT_PACK32,  4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8_TYPELESS,         VK_FORMAT_R8G8_UNORM,               2,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R8G8_UNORM,            VK_FORMAT_R8G8_UNORM,               2,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8_UINT,             VK_FORMAT_R8G8_UINT,                2,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R8G8_SNORM,            VK_FORMAT_R8G8_SNORM,               2,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8_SINT,             VK_FORMAT_R8G8_SINT,                2,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R8G8B8A8_TYPELESS,     VK_FORMAT_R8G8B8A8_UNORM,           4,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R8G8B8A8_UNORM,        VK_FORMAT_R8G8B8A8_UNORM,           4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,   VK_FORMAT_R8G8B8A8_SRGB,            4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8B8A8_UINT,         VK_FORMAT_R8G8B8A8_UINT,            4,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R8G8B8A8_SNORM,        VK_FORMAT_R8G8B8A8_SNORM,           4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8G8B8A8_SINT,         VK_FORMAT_R8G8B8A8_SINT,            4,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R16G16_TYPELESS,       VK_FORMAT_R16G16_SFLOAT,            4,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R16G16_FLOAT,          VK_FORMAT_R16G16_SFLOAT,            4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16_UNORM,          VK_FORMAT_R16G16_UNORM,             4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16_UINT,           VK_FORMAT_R16G16_UINT,              4,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R16G16_SNORM,          VK_FORMAT_R16G16_SNORM,             4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16G16_SINT,           VK_FORMAT_R16G16_SINT,              4,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R32_TYPELESS,          VK_FORMAT_R32_UINT,                 4,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_D32_FLOAT,             VK_FORMAT_D32_SFLOAT,               4,  1, 1,  1, DEPTH, 1},
+    {DXGI_FORMAT_R32_FLOAT,             VK_FORMAT_R32_SFLOAT,               4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R32_UINT,              VK_FORMAT_R32_UINT,                 4,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R32_SINT,              VK_FORMAT_R32_SINT,                 4,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R16_TYPELESS,          VK_FORMAT_R16_UINT,                 2,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R16_FLOAT,             VK_FORMAT_R16_SFLOAT,               2,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_D16_UNORM,             VK_FORMAT_D16_UNORM,                2,  1, 1,  1, DEPTH, 1},
+    {DXGI_FORMAT_R16_UNORM,             VK_FORMAT_R16_UNORM,                2,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16_UINT,              VK_FORMAT_R16_UINT,                 2,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R16_SNORM,             VK_FORMAT_R16_SNORM,                2,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R16_SINT,              VK_FORMAT_R16_SINT,                 2,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_R8_TYPELESS,           VK_FORMAT_R8_UNORM,                 1,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_R8_UNORM,              VK_FORMAT_R8_UNORM,                 1,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8_UINT,               VK_FORMAT_R8_UINT,                  1,  1, 1,  1, COLOR, 1, UINT},
+    {DXGI_FORMAT_R8_SNORM,              VK_FORMAT_R8_SNORM,                 1,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_R8_SINT,               VK_FORMAT_R8_SINT,                  1,  1, 1,  1, COLOR, 1, SINT},
+    {DXGI_FORMAT_A8_UNORM,              VK_FORMAT_R8_UNORM,                 1,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_B8G8R8A8_UNORM,        VK_FORMAT_B8G8R8A8_UNORM,           4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_B8G8R8X8_UNORM,        VK_FORMAT_B8G8R8A8_UNORM,           4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_B8G8R8A8_TYPELESS,     VK_FORMAT_B8G8R8A8_UNORM,           4,  1, 1,  1, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,   VK_FORMAT_B8G8R8A8_SRGB,            4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_B8G8R8X8_TYPELESS,     VK_FORMAT_B8G8R8A8_UNORM,           4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,   VK_FORMAT_B8G8R8A8_SRGB,            4,  1, 1,  1, COLOR, 1},
+    {DXGI_FORMAT_BC1_TYPELESS,          VK_FORMAT_BC1_RGBA_UNORM_BLOCK,     1,  4, 4,  8, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC1_UNORM,             VK_FORMAT_BC1_RGBA_UNORM_BLOCK,     1,  4, 4,  8, COLOR, 1},
+    {DXGI_FORMAT_BC1_UNORM_SRGB,        VK_FORMAT_BC1_RGBA_SRGB_BLOCK,      1,  4, 4,  8, COLOR, 1},
+    {DXGI_FORMAT_BC2_TYPELESS,          VK_FORMAT_BC2_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC2_UNORM,             VK_FORMAT_BC2_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC2_UNORM_SRGB,        VK_FORMAT_BC2_SRGB_BLOCK,           1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC3_TYPELESS,          VK_FORMAT_BC3_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC3_UNORM,             VK_FORMAT_BC3_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC3_UNORM_SRGB,        VK_FORMAT_BC3_SRGB_BLOCK,           1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC4_TYPELESS,          VK_FORMAT_BC4_UNORM_BLOCK,          1,  4, 4,  8, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC4_UNORM,             VK_FORMAT_BC4_UNORM_BLOCK,          1,  4, 4,  8, COLOR, 1},
+    {DXGI_FORMAT_BC4_SNORM,             VK_FORMAT_BC4_SNORM_BLOCK,          1,  4, 4,  8, COLOR, 1},
+    {DXGI_FORMAT_BC5_TYPELESS,          VK_FORMAT_BC5_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC5_UNORM,             VK_FORMAT_BC5_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC5_SNORM,             VK_FORMAT_BC5_SNORM_BLOCK,          1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC6H_TYPELESS,         VK_FORMAT_BC6H_UFLOAT_BLOCK,        1,  4, 4, 16, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC6H_UF16,             VK_FORMAT_BC6H_UFLOAT_BLOCK,        1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC6H_SF16,             VK_FORMAT_BC6H_SFLOAT_BLOCK,        1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC7_TYPELESS,          VK_FORMAT_BC7_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1, TYPELESS},
+    {DXGI_FORMAT_BC7_UNORM,             VK_FORMAT_BC7_UNORM_BLOCK,          1,  4, 4, 16, COLOR, 1},
+    {DXGI_FORMAT_BC7_UNORM_SRGB,        VK_FORMAT_BC7_SRGB_BLOCK,           1,  4, 4, 16, COLOR, 1},
+};
+
+/* Each depth/stencil format is only compatible with itself in Vulkan. */
+static const struct vkd3d_format vkd3d_depth_stencil_formats[] =
+{
+    {DXGI_FORMAT_R32G8X24_TYPELESS,        VK_FORMAT_D32_SFLOAT_S8_UINT, 8,  1, 1, 1, DEPTH_STENCIL, 2, TYPELESS},
+    {DXGI_FORMAT_D32_FLOAT_S8X24_UINT,     VK_FORMAT_D32_SFLOAT_S8_UINT, 8,  1, 1, 1, DEPTH_STENCIL, 2},
+    {DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, 8,  1, 1, 1, DEPTH,         2},
+    {DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,  VK_FORMAT_D32_SFLOAT_S8_UINT, 8,  1, 1, 1, STENCIL,       2},
+    {DXGI_FORMAT_R32_TYPELESS,             VK_FORMAT_D32_SFLOAT,         4,  1, 1, 1, DEPTH,         1, TYPELESS},
+    {DXGI_FORMAT_R32_FLOAT,                VK_FORMAT_D32_SFLOAT,         4,  1, 1, 1, DEPTH,         1},
+    {DXGI_FORMAT_R24G8_TYPELESS,           VK_FORMAT_D24_UNORM_S8_UINT,  4,  1, 1, 1, DEPTH_STENCIL, 2, TYPELESS},
+    {DXGI_FORMAT_D24_UNORM_S8_UINT,        VK_FORMAT_D24_UNORM_S8_UINT,  4,  1, 1, 1, DEPTH_STENCIL, 2},
+    {DXGI_FORMAT_R24_UNORM_X8_TYPELESS,    VK_FORMAT_D24_UNORM_S8_UINT,  4,  1, 1, 1, DEPTH,         2},
+    {DXGI_FORMAT_X24_TYPELESS_G8_UINT,     VK_FORMAT_D24_UNORM_S8_UINT,  4,  1, 1, 1, STENCIL,       2},
+    {DXGI_FORMAT_R16_TYPELESS,             VK_FORMAT_D16_UNORM,          2,  1, 1, 1, DEPTH,         1, TYPELESS},
+    {DXGI_FORMAT_R16_UNORM,                VK_FORMAT_D16_UNORM,          2,  1, 1, 1, DEPTH,         1},
+};
+#undef COLOR
+#undef DEPTH
+#undef STENCIL
+#undef DEPTH_STENCIL
+#undef TYPELESS
+#undef SINT
+#undef UINT
+
+static const struct vkd3d_format_compatibility_info
+{
+    DXGI_FORMAT format;
+    DXGI_FORMAT typeless_format;
+}
+vkd3d_format_compatibility_info[] =
+{
+    /* DXGI_FORMAT_R32G32B32A32_TYPELESS */
+    {DXGI_FORMAT_R32G32B32A32_UINT,        DXGI_FORMAT_R32G32B32A32_TYPELESS},
+    {DXGI_FORMAT_R32G32B32A32_SINT,        DXGI_FORMAT_R32G32B32A32_TYPELESS},
+    {DXGI_FORMAT_R32G32B32A32_FLOAT,       DXGI_FORMAT_R32G32B32A32_TYPELESS},
+    /* DXGI_FORMAT_R32G32B32_TYPELESS */
+    {DXGI_FORMAT_R32G32B32_UINT,           DXGI_FORMAT_R32G32B32_TYPELESS},
+    {DXGI_FORMAT_R32G32B32_SINT,           DXGI_FORMAT_R32G32B32_TYPELESS},
+    {DXGI_FORMAT_R32G32B32_FLOAT,          DXGI_FORMAT_R32G32B32_TYPELESS},
+    /* DXGI_FORMAT_R16G16B16A16_TYPELESS */
+    {DXGI_FORMAT_R16G16B16A16_UNORM,       DXGI_FORMAT_R16G16B16A16_TYPELESS},
+    {DXGI_FORMAT_R16G16B16A16_SNORM,       DXGI_FORMAT_R16G16B16A16_TYPELESS},
+    {DXGI_FORMAT_R16G16B16A16_UINT,        DXGI_FORMAT_R16G16B16A16_TYPELESS},
+    {DXGI_FORMAT_R16G16B16A16_SINT,        DXGI_FORMAT_R16G16B16A16_TYPELESS},
+    {DXGI_FORMAT_R16G16B16A16_FLOAT,       DXGI_FORMAT_R16G16B16A16_TYPELESS},
+    /* DXGI_FORMAT_R32G32_TYPELESS */
+    {DXGI_FORMAT_R32G32_UINT,              DXGI_FORMAT_R32G32_TYPELESS},
+    {DXGI_FORMAT_R32G32_SINT,              DXGI_FORMAT_R32G32_TYPELESS},
+    {DXGI_FORMAT_R32G32_FLOAT,             DXGI_FORMAT_R32G32_TYPELESS},
+    /* DXGI_FORMAT_R32G8X24_TYPELESS */
+    {DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_R32G8X24_TYPELESS},
+    {DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,  DXGI_FORMAT_R32G8X24_TYPELESS},
+    {DXGI_FORMAT_D32_FLOAT_S8X24_UINT,     DXGI_FORMAT_R32G8X24_TYPELESS},
+    /* DXGI_FORMAT_R10G10B10A2_TYPELESS */
+    {DXGI_FORMAT_R10G10B10A2_UINT,         DXGI_FORMAT_R10G10B10A2_TYPELESS},
+    {DXGI_FORMAT_R10G10B10A2_UNORM,        DXGI_FORMAT_R10G10B10A2_TYPELESS},
+    /* DXGI_FORMAT_R8G8B8A8_TYPELESS */
+    {DXGI_FORMAT_R8G8B8A8_UINT,            DXGI_FORMAT_R8G8B8A8_TYPELESS},
+    {DXGI_FORMAT_R8G8B8A8_SINT,            DXGI_FORMAT_R8G8B8A8_TYPELESS},
+    {DXGI_FORMAT_R8G8B8A8_SNORM,           DXGI_FORMAT_R8G8B8A8_TYPELESS},
+    {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,      DXGI_FORMAT_R8G8B8A8_TYPELESS},
+    {DXGI_FORMAT_R8G8B8A8_UNORM,           DXGI_FORMAT_R8G8B8A8_TYPELESS},
+    /* DXGI_FORMAT_R16G16_TYPELESS */
+    {DXGI_FORMAT_R16G16_UNORM,             DXGI_FORMAT_R16G16_TYPELESS},
+    {DXGI_FORMAT_R16G16_SNORM,             DXGI_FORMAT_R16G16_TYPELESS},
+    {DXGI_FORMAT_R16G16_UINT,              DXGI_FORMAT_R16G16_TYPELESS},
+    {DXGI_FORMAT_R16G16_SINT,              DXGI_FORMAT_R16G16_TYPELESS},
+    {DXGI_FORMAT_R16G16_FLOAT,             DXGI_FORMAT_R16G16_TYPELESS},
+    /* DXGI_FORMAT_R32_TYPELESS */
+    {DXGI_FORMAT_D32_FLOAT,                DXGI_FORMAT_R32_TYPELESS},
+    {DXGI_FORMAT_R32_FLOAT,                DXGI_FORMAT_R32_TYPELESS},
+    {DXGI_FORMAT_R32_UINT,                 DXGI_FORMAT_R32_TYPELESS},
+    {DXGI_FORMAT_R32_SINT,                 DXGI_FORMAT_R32_TYPELESS},
+    /* DXGI_FORMAT_R24G8_TYPELESS */
+    {DXGI_FORMAT_R24_UNORM_X8_TYPELESS,    DXGI_FORMAT_R24G8_TYPELESS},
+    {DXGI_FORMAT_X24_TYPELESS_G8_UINT,     DXGI_FORMAT_R24G8_TYPELESS},
+    {DXGI_FORMAT_D24_UNORM_S8_UINT,        DXGI_FORMAT_R24G8_TYPELESS},
+    /* DXGI_FORMAT_R8G8_TYPELESS */
+    {DXGI_FORMAT_R8G8_SNORM,               DXGI_FORMAT_R8G8_TYPELESS},
+    {DXGI_FORMAT_R8G8_UNORM,               DXGI_FORMAT_R8G8_TYPELESS},
+    {DXGI_FORMAT_R8G8_UINT,                DXGI_FORMAT_R8G8_TYPELESS},
+    {DXGI_FORMAT_R8G8_SINT,                DXGI_FORMAT_R8G8_TYPELESS},
+    /* DXGI_FORMAT_R16_TYPELESS */
+    {DXGI_FORMAT_D16_UNORM,                DXGI_FORMAT_R16_TYPELESS},
+    {DXGI_FORMAT_R16_UNORM,                DXGI_FORMAT_R16_TYPELESS},
+    {DXGI_FORMAT_R16_SNORM,                DXGI_FORMAT_R16_TYPELESS},
+    {DXGI_FORMAT_R16_UINT,                 DXGI_FORMAT_R16_TYPELESS},
+    {DXGI_FORMAT_R16_SINT,                 DXGI_FORMAT_R16_TYPELESS},
+    {DXGI_FORMAT_R16_FLOAT,                DXGI_FORMAT_R16_TYPELESS},
+    /* DXGI_FORMAT_R8_TYPELESS */
+    {DXGI_FORMAT_R8_UNORM,                 DXGI_FORMAT_R8_TYPELESS},
+    {DXGI_FORMAT_R8_SNORM,                 DXGI_FORMAT_R8_TYPELESS},
+    {DXGI_FORMAT_R8_UINT,                  DXGI_FORMAT_R8_TYPELESS},
+    {DXGI_FORMAT_R8_SINT,                  DXGI_FORMAT_R8_TYPELESS},
+    /* DXGI_FORMAT_BC1_TYPELESS */
+    {DXGI_FORMAT_BC1_UNORM_SRGB,           DXGI_FORMAT_BC1_TYPELESS},
+    {DXGI_FORMAT_BC1_UNORM,                DXGI_FORMAT_BC1_TYPELESS},
+    /* DXGI_FORMAT_BC2_TYPELESS */
+    {DXGI_FORMAT_BC2_UNORM_SRGB,           DXGI_FORMAT_BC2_TYPELESS},
+    {DXGI_FORMAT_BC2_UNORM,                DXGI_FORMAT_BC2_TYPELESS},
+    /* DXGI_FORMAT_BC3_TYPELESS */
+    {DXGI_FORMAT_BC3_UNORM_SRGB,           DXGI_FORMAT_BC3_TYPELESS},
+    {DXGI_FORMAT_BC3_UNORM,                DXGI_FORMAT_BC3_TYPELESS},
+    /* DXGI_FORMAT_BC4_TYPELESS */
+    {DXGI_FORMAT_BC4_UNORM,                DXGI_FORMAT_BC4_TYPELESS},
+    {DXGI_FORMAT_BC4_SNORM,                DXGI_FORMAT_BC4_TYPELESS},
+    /* DXGI_FORMAT_BC5_TYPELESS */
+    {DXGI_FORMAT_BC5_UNORM,                DXGI_FORMAT_BC5_TYPELESS},
+    {DXGI_FORMAT_BC5_SNORM,                DXGI_FORMAT_BC5_TYPELESS},
+    /* DXGI_FORMAT_BC6H_TYPELESS */
+    {DXGI_FORMAT_BC6H_UF16,                DXGI_FORMAT_BC6H_TYPELESS},
+    {DXGI_FORMAT_BC6H_SF16,                DXGI_FORMAT_BC6H_TYPELESS},
+    /* DXGI_FORMAT_BC7_TYPELESS */
+    {DXGI_FORMAT_BC7_UNORM_SRGB,           DXGI_FORMAT_BC7_TYPELESS},
+    {DXGI_FORMAT_BC7_UNORM,                DXGI_FORMAT_BC7_TYPELESS},
+    /* DXGI_FORMAT_B8G8R8A8_TYPELESS */
+    {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,      DXGI_FORMAT_B8G8R8A8_TYPELESS},
+    {DXGI_FORMAT_B8G8R8A8_UNORM,           DXGI_FORMAT_B8G8R8A8_TYPELESS},
+    /* DXGI_FORMAT_B8G8R8X8_TYPELESS */
+    {DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,      DXGI_FORMAT_B8G8R8X8_TYPELESS},
+    {DXGI_FORMAT_B8G8R8X8_UNORM,           DXGI_FORMAT_B8G8R8X8_TYPELESS},
+};
+
+static bool dxgi_format_is_depth_stencil(DXGI_FORMAT dxgi_format)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_formats); ++i)
+    {
+        const struct vkd3d_format *current = &vkd3d_formats[i];
+
+        if (current->dxgi_format == dxgi_format)
+            return current->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_depth_stencil_formats); ++i)
+    {
+        if (vkd3d_depth_stencil_formats[i].dxgi_format == dxgi_format)
+            return true;
+    }
+
+    return false;
+}
+
+/* FIXME: This table should be generated at compile-time. */
+static HRESULT vkd3d_init_format_compatibility_lists(struct d3d12_device *device)
+{
+    struct vkd3d_format_compatibility_list *lists, *current_list;
+    const struct vkd3d_format_compatibility_info *current;
+    DXGI_FORMAT dxgi_format;
+    VkFormat vk_format;
+    unsigned int count;
+    unsigned int i, j;
+
+    device->format_compatibility_list_count = 0;
+    device->format_compatibility_lists = NULL;
+
+    if (!device->vk_info.KHR_image_format_list)
+        return S_OK;
+
+    count = 1;
+    dxgi_format = vkd3d_format_compatibility_info[0].typeless_format;
+    for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i)
+    {
+        DXGI_FORMAT typeless_format = vkd3d_format_compatibility_info[i].typeless_format;
+
+        if (dxgi_format != typeless_format)
+        {
+            ++count;
+            dxgi_format = typeless_format;
+        }
+    }
+
+    if (!(lists = vkd3d_calloc(count, sizeof(*lists))))
+        return E_OUTOFMEMORY;
+
+    count = 0;
+    current_list = lists;
+    current_list->typeless_format = vkd3d_format_compatibility_info[0].typeless_format;
+    for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i)
+    {
+        current = &vkd3d_format_compatibility_info[i];
+
+        if (current_list->typeless_format != current->typeless_format)
+        {
+            /* Avoid empty format lists. */
+            if (current_list->format_count)
+            {
+                ++current_list;
+                ++count;
+            }
+
+            current_list->typeless_format = current->typeless_format;
+        }
+
+        /* In Vulkan, each depth-stencil format is only compatible with itself. */
+        if (dxgi_format_is_depth_stencil(current->format))
+            continue;
+
+        if (!(vk_format = vkd3d_get_vk_format(current->format)))
+            continue;
+
+        for (j = 0; j < current_list->format_count; ++j)
+        {
+            if (current_list->vk_formats[j] == vk_format)
+                break;
+        }
+
+        if (j >= current_list->format_count)
+        {
+            assert(current_list->format_count < VKD3D_MAX_COMPATIBLE_FORMAT_COUNT);
+            current_list->vk_formats[current_list->format_count++] = vk_format;
+        }
+    }
+    if (current_list->format_count)
+        ++count;
+
+    device->format_compatibility_list_count = count;
+    device->format_compatibility_lists = lists;
+    return S_OK;
+}
+
+static void vkd3d_cleanup_format_compatibility_lists(struct d3d12_device *device)
+{
+    vkd3d_free((void *)device->format_compatibility_lists);
+
+    device->format_compatibility_lists = NULL;
+    device->format_compatibility_list_count = 0;
+}
+
+static HRESULT vkd3d_init_depth_stencil_formats(struct d3d12_device *device)
+{
+    const unsigned int count = ARRAY_SIZE(vkd3d_depth_stencil_formats);
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkFormatProperties properties;
+    struct vkd3d_format *formats;
+    unsigned int i;
+
+    VK_CALL(vkGetPhysicalDeviceFormatProperties(device->vk_physical_device,
+            VK_FORMAT_D24_UNORM_S8_UINT, &properties));
+
+    if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
+    {
+        device->depth_stencil_formats = vkd3d_depth_stencil_formats;
+    }
+    else
+    {
+        /* AMD doesn't support VK_FORMAT_D24_UNORM_S8_UINT. */
+        WARN("Mapping VK_FORMAT_D24_UNORM_S8_UINT to VK_FORMAT_D32_SFLOAT_S8_UINT.\n");
+
+        if (!(formats = vkd3d_calloc(count, sizeof(*formats))))
+            return E_OUTOFMEMORY;
+
+        memcpy(formats, vkd3d_depth_stencil_formats, sizeof(vkd3d_depth_stencil_formats));
+        for (i = 0; i < count; ++i)
+        {
+            if (formats[i].vk_format == VK_FORMAT_D24_UNORM_S8_UINT)
+            {
+                formats[i].vk_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
+                formats[i].is_emulated = true;
+            }
+        }
+
+        device->depth_stencil_formats = formats;
+    }
+
+    return S_OK;
+}
+
+static void vkd3d_cleanup_depth_stencil_formats(struct d3d12_device *device)
+{
+    if (vkd3d_depth_stencil_formats != device->depth_stencil_formats)
+        vkd3d_free((void *)device->depth_stencil_formats);
+
+    device->depth_stencil_formats = NULL;
+}
+
+HRESULT vkd3d_init_format_info(struct d3d12_device *device)
+{
+    HRESULT hr;
+
+    if (FAILED(hr = vkd3d_init_depth_stencil_formats(device)))
+        return hr;
+
+    if FAILED(hr = vkd3d_init_format_compatibility_lists(device))
+        vkd3d_cleanup_depth_stencil_formats(device);
+
+    return hr;
+}
+
+void vkd3d_cleanup_format_info(struct d3d12_device *device)
+{
+    vkd3d_cleanup_depth_stencil_formats(device);
+    vkd3d_cleanup_format_compatibility_lists(device);
+}
+
+/* We use overrides for depth/stencil formats. This is required in order to
+ * properly support typeless formats because depth/stencil formats are only
+ * compatible with themselves in Vulkan.
+ */
+static const struct vkd3d_format *vkd3d_get_depth_stencil_format(const struct d3d12_device *device,
+        DXGI_FORMAT dxgi_format)
+{
+    const struct vkd3d_format *formats;
+    unsigned int i;
+
+    assert(device);
+    formats = device->depth_stencil_formats;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_depth_stencil_formats); ++i)
+    {
+        if (formats[i].dxgi_format == dxgi_format)
+            return &formats[i];
+    }
+
+    return NULL;
+}
+
+const struct vkd3d_format *vkd3d_get_format(const struct d3d12_device *device,
+        DXGI_FORMAT dxgi_format, bool depth_stencil)
+{
+    const struct vkd3d_format *format;
+    unsigned int i;
+
+    if (depth_stencil && (format = vkd3d_get_depth_stencil_format(device, dxgi_format)))
+        return format;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_formats); ++i)
+    {
+        if (vkd3d_formats[i].dxgi_format == dxgi_format)
+            return &vkd3d_formats[i];
+    }
+
+    return NULL;
+}
+
+const struct vkd3d_format *vkd3d_find_uint_format(const struct d3d12_device *device, DXGI_FORMAT dxgi_format)
+{
+    DXGI_FORMAT typeless_format = DXGI_FORMAT_UNKNOWN;
+    const struct vkd3d_format *vkd3d_format;
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i)
+    {
+        if (vkd3d_format_compatibility_info[i].format == dxgi_format)
+        {
+            typeless_format = vkd3d_format_compatibility_info[i].typeless_format;
+            break;
+        }
+    }
+
+    if (!typeless_format)
+        return NULL;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i)
+    {
+        if (vkd3d_format_compatibility_info[i].typeless_format != typeless_format)
+            continue;
+
+        vkd3d_format = vkd3d_get_format(device, vkd3d_format_compatibility_info[i].format, false);
+        if (vkd3d_format->type == VKD3D_FORMAT_TYPE_UINT)
+            return vkd3d_format;
+    }
+
+    return NULL;
+}
+
+void vkd3d_format_copy_data(const struct vkd3d_format *format, const uint8_t *src,
+        unsigned int src_row_pitch, unsigned int src_slice_pitch, uint8_t *dst, unsigned int dst_row_pitch,
+        unsigned int dst_slice_pitch, unsigned int w, unsigned int h, unsigned int d)
+{
+    unsigned int row_block_count, row_count, row_size, slice, row;
+    unsigned int slice_count = d;
+    const uint8_t *src_row;
+    uint8_t *dst_row;
+
+    row_block_count = (w + format->block_width - 1) / format->block_width;
+    row_count = (h + format->block_height - 1) / format->block_height;
+    row_size = row_block_count * format->byte_count * format->block_byte_count;
+
+    for (slice = 0; slice < slice_count; ++slice)
+    {
+        for (row = 0; row < row_count; ++row)
+        {
+            src_row = &src[slice * src_slice_pitch + row * src_row_pitch];
+            dst_row = &dst[slice * dst_slice_pitch + row * dst_row_pitch];
+            memcpy(dst_row, src_row, row_size);
+        }
+    }
+}
+
+VkFormat vkd3d_get_vk_format(DXGI_FORMAT format)
+{
+    const struct vkd3d_format *vkd3d_format;
+
+    if (!(vkd3d_format = vkd3d_get_format(NULL, format, false)))
+        return VK_FORMAT_UNDEFINED;
+
+    return vkd3d_format->vk_format;
+}
+
+DXGI_FORMAT vkd3d_get_dxgi_format(VkFormat format)
+{
+    DXGI_FORMAT dxgi_format;
+    VkFormat vk_format;
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(vkd3d_formats); ++i)
+    {
+        vk_format = vkd3d_formats[i].vk_format;
+        dxgi_format = vkd3d_formats[i].dxgi_format;
+        if (vk_format == format && vkd3d_formats[i].type != VKD3D_FORMAT_TYPE_TYPELESS)
+            return dxgi_format;
+    }
+
+    FIXME("Unhandled Vulkan format %#x.\n", format);
+    return DXGI_FORMAT_UNKNOWN;
+}
+
+bool is_valid_feature_level(D3D_FEATURE_LEVEL feature_level)
+{
+    static const D3D_FEATURE_LEVEL valid_feature_levels[] =
+    {
+        D3D_FEATURE_LEVEL_12_1,
+        D3D_FEATURE_LEVEL_12_0,
+        D3D_FEATURE_LEVEL_11_1,
+        D3D_FEATURE_LEVEL_11_0,
+        D3D_FEATURE_LEVEL_10_1,
+        D3D_FEATURE_LEVEL_10_0,
+        D3D_FEATURE_LEVEL_9_3,
+        D3D_FEATURE_LEVEL_9_2,
+        D3D_FEATURE_LEVEL_9_1,
+    };
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(valid_feature_levels); ++i)
+    {
+        if (valid_feature_levels[i] == feature_level)
+            return true;
+    }
+
+    return false;
+}
+
+bool is_write_resource_state(D3D12_RESOURCE_STATES state)
+{
+    return state & (D3D12_RESOURCE_STATE_RENDER_TARGET
+            | D3D12_RESOURCE_STATE_UNORDERED_ACCESS
+            | D3D12_RESOURCE_STATE_DEPTH_WRITE
+            | D3D12_RESOURCE_STATE_STREAM_OUT
+            | D3D12_RESOURCE_STATE_COPY_DEST
+            | D3D12_RESOURCE_STATE_RESOLVE_DEST);
+}
+
+static bool is_power_of_two(unsigned int x)
+{
+    return x && !(x & (x -1));
+}
+
+bool is_valid_resource_state(D3D12_RESOURCE_STATES state)
+{
+    const D3D12_RESOURCE_STATES valid_states =
+            D3D12_RESOURCE_STATE_COMMON |
+            D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER |
+            D3D12_RESOURCE_STATE_INDEX_BUFFER |
+            D3D12_RESOURCE_STATE_RENDER_TARGET |
+            D3D12_RESOURCE_STATE_UNORDERED_ACCESS |
+            D3D12_RESOURCE_STATE_DEPTH_WRITE |
+            D3D12_RESOURCE_STATE_DEPTH_READ |
+            D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
+            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
+            D3D12_RESOURCE_STATE_STREAM_OUT |
+            D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT |
+            D3D12_RESOURCE_STATE_COPY_DEST |
+            D3D12_RESOURCE_STATE_COPY_SOURCE |
+            D3D12_RESOURCE_STATE_RESOLVE_DEST |
+            D3D12_RESOURCE_STATE_RESOLVE_SOURCE |
+            D3D12_RESOURCE_STATE_GENERIC_READ |
+            D3D12_RESOURCE_STATE_PRESENT |
+            D3D12_RESOURCE_STATE_PREDICATION;
+
+    if (state & ~valid_states)
+    {
+        WARN("Invalid resource states %#x.\n", state & ~valid_states);
+        return false;
+    }
+
+    /* Exactly one bit must be set for write states. */
+    if (is_write_resource_state(state) && !is_power_of_two(state))
+    {
+        WARN("Write state cannot be mixed with other states: %#x.\n", state);
+        return false;
+    }
+
+    return true;
+}
+
+HRESULT return_interface(void *iface, REFIID iface_iid,
+        REFIID requested_iid, void **object)
+{
+    IUnknown *unknown = iface;
+    HRESULT hr;
+
+    if (IsEqualGUID(iface_iid, requested_iid))
+    {
+        *object = unknown;
+        return S_OK;
+    }
+
+    hr = IUnknown_QueryInterface(unknown, requested_iid, object);
+    IUnknown_Release(unknown);
+    return hr;
+}
+
+const char *debug_d3d12_box(const D3D12_BOX *box)
+{
+    if (!box)
+        return "(null)";
+
+    return vkd3d_dbg_sprintf("(%u, %u, %u)-(%u, %u, %u)",
+            box->left, box->top, box->front,
+            box->right, box->bottom, box->back);
+}
+
+static const char *debug_d3d12_shader_component(D3D12_SHADER_COMPONENT_MAPPING component)
+{
+    switch (component)
+    {
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0:
+            return "r";
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1:
+            return "g";
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2:
+            return "b";
+        case D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3:
+            return "a";
+        case D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0:
+            return "0";
+        case D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1:
+            return "1";
+    }
+
+    FIXME("Invalid component mapping %#x.\n", component);
+    return "invalid";
+}
+
+const char *debug_d3d12_shader_component_mapping(unsigned int mapping)
+{
+    return vkd3d_dbg_sprintf("{%s, %s, %s, %s}",
+            debug_d3d12_shader_component(D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, mapping)),
+            debug_d3d12_shader_component(D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, mapping)),
+            debug_d3d12_shader_component(D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, mapping)),
+            debug_d3d12_shader_component(D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, mapping)));
+}
+
+const char *debug_vk_extent_3d(VkExtent3D extent)
+{
+    return vkd3d_dbg_sprintf("(%u, %u, %u)",
+            (unsigned int)extent.width,
+            (unsigned int)extent.height,
+            (unsigned int)extent.depth);
+}
+
+const char *debug_vk_queue_flags(VkQueueFlags flags)
+{
+    char buffer[120];
+
+    buffer[0] = '\0';
+#define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; }
+    FLAG_TO_STR(VK_QUEUE_GRAPHICS_BIT)
+    FLAG_TO_STR(VK_QUEUE_COMPUTE_BIT)
+    FLAG_TO_STR(VK_QUEUE_TRANSFER_BIT)
+    FLAG_TO_STR(VK_QUEUE_SPARSE_BINDING_BIT)
+#undef FLAG_TO_STR
+    if (flags)
+        FIXME("Unrecognized flag(s) %#x.\n", flags);
+
+    if (!buffer[0])
+        return "0";
+    return vkd3d_dbg_sprintf("%s", &buffer[3]);
+}
+
+const char *debug_vk_memory_heap_flags(VkMemoryHeapFlags flags)
+{
+    char buffer[80];
+
+    buffer[0] = '\0';
+#define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; }
+    FLAG_TO_STR(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
+    FLAG_TO_STR(VK_MEMORY_HEAP_MULTI_INSTANCE_BIT)
+#undef FLAG_TO_STR
+    if (flags)
+        FIXME("Unrecognized flag(s) %#x.\n", flags);
+
+    if (!buffer[0])
+        return "0";
+    return vkd3d_dbg_sprintf("%s", &buffer[3]);
+}
+
+const char *debug_vk_memory_property_flags(VkMemoryPropertyFlags flags)
+{
+    char buffer[200];
+
+    buffer[0] = '\0';
+#define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; }
+    FLAG_TO_STR(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+    FLAG_TO_STR(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+    FLAG_TO_STR(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
+    FLAG_TO_STR(VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
+    FLAG_TO_STR(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
+#undef FLAG_TO_STR
+    if (flags)
+        FIXME("Unrecognized flag(s) %#x.\n", flags);
+
+    if (!buffer[0])
+        return "0";
+    return vkd3d_dbg_sprintf("%s", &buffer[3]);
+}
+
+HRESULT hresult_from_errno(int rc)
+{
+    switch (rc)
+    {
+        case 0:
+            return S_OK;
+        case ENOMEM:
+            return E_OUTOFMEMORY;
+        case EINVAL:
+            return E_INVALIDARG;
+        default:
+            FIXME("Unhandled errno %d.\n", rc);
+            return E_FAIL;
+    }
+}
+
+HRESULT hresult_from_vk_result(VkResult vr)
+{
+    switch (vr)
+    {
+        case VK_SUCCESS:
+            return S_OK;
+        case VK_ERROR_OUT_OF_DEVICE_MEMORY:
+            WARN("Out of device memory.\n");
+            /* fall-through */
+        case VK_ERROR_OUT_OF_HOST_MEMORY:
+            return E_OUTOFMEMORY;
+        default:
+            FIXME("Unhandled VkResult %d.\n", vr);
+            /* fall-through */
+        case VK_ERROR_DEVICE_LOST:
+        case VK_ERROR_EXTENSION_NOT_PRESENT:
+            return E_FAIL;
+    }
+}
+
+HRESULT hresult_from_vkd3d_result(int vkd3d_result)
+{
+    switch (vkd3d_result)
+    {
+        case VKD3D_OK:
+            return S_OK;
+        case VKD3D_ERROR_INVALID_SHADER:
+            WARN("Invalid shader bytecode.\n");
+            /* fall-through */
+        case VKD3D_ERROR:
+            return E_FAIL;
+        case VKD3D_ERROR_OUT_OF_MEMORY:
+            return E_OUTOFMEMORY;
+        case VKD3D_ERROR_INVALID_ARGUMENT:
+            return E_INVALIDARG;
+        case VKD3D_ERROR_NOT_IMPLEMENTED:
+            return E_NOTIMPL;
+        default:
+            FIXME("Unhandled vkd3d result %d.\n", vkd3d_result);
+            return E_FAIL;
+    }
+}
+
+#define LOAD_GLOBAL_PFN(name) \
+    if (!(procs->name = (void *)vkGetInstanceProcAddr(NULL, #name))) \
+    { \
+        ERR("Could not get global proc addr for '" #name "'.\n"); \
+        return E_FAIL; \
+    }
+
+HRESULT vkd3d_load_vk_global_procs(struct vkd3d_vk_global_procs *procs,
+        PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr)
+{
+    memset(procs, 0, sizeof(*procs));
+
+    procs->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
+
+    LOAD_GLOBAL_PFN(vkCreateInstance)
+    LOAD_GLOBAL_PFN(vkEnumerateInstanceExtensionProperties)
+
+    TRACE("Loaded global Vulkan procs.\n");
+    return S_OK;
+}
+
+#define LOAD_INSTANCE_PFN(name) \
+    if (!(procs->name = (void *)global_procs->vkGetInstanceProcAddr(instance, #name))) \
+    { \
+        ERR("Could not get instance proc addr for '" #name "'.\n"); \
+        return E_FAIL; \
+    }
+#define LOAD_INSTANCE_OPTIONAL_PFN(name) \
+    procs->name = (void *)global_procs->vkGetInstanceProcAddr(instance, #name);
+
+HRESULT vkd3d_load_vk_instance_procs(struct vkd3d_vk_instance_procs *procs,
+        const struct vkd3d_vk_global_procs *global_procs, VkInstance instance)
+{
+    memset(procs, 0, sizeof(*procs));
+
+#define VK_INSTANCE_PFN     LOAD_INSTANCE_PFN
+#define VK_INSTANCE_EXT_PFN LOAD_INSTANCE_OPTIONAL_PFN
+#include "vulkan_procs.h"
+
+    TRACE("Loaded procs for VkInstance %p.\n", instance);
+    return S_OK;
+}
+
+#define COPY_PARENT_PFN(name) procs->name = parent_procs->name;
+#define LOAD_DEVICE_PFN(name) \
+    if (!(procs->name = (void *)procs->vkGetDeviceProcAddr(device, #name))) \
+    { \
+        ERR("Could not get device proc addr for '" #name "'.\n"); \
+        return E_FAIL; \
+    }
+#define LOAD_DEVICE_OPTIONAL_PFN(name) \
+    procs->name = (void *)procs->vkGetDeviceProcAddr(device, #name);
+
+HRESULT vkd3d_load_vk_device_procs(struct vkd3d_vk_device_procs *procs,
+        const struct vkd3d_vk_instance_procs *parent_procs, VkDevice device)
+{
+    memset(procs, 0, sizeof(*procs));
+
+#define VK_INSTANCE_PFN   COPY_PARENT_PFN
+#define VK_DEVICE_PFN     LOAD_DEVICE_PFN
+#define VK_DEVICE_EXT_PFN LOAD_DEVICE_OPTIONAL_PFN
+#include "vulkan_procs.h"
+
+    TRACE("Loaded procs for VkDevice %p.\n", device);
+    return S_OK;
+}
+
+#if HAVE_DECL_PROGRAM_INVOCATION_NAME
+
+bool vkd3d_get_program_name(char program_name[PATH_MAX])
+{
+    char *name, *p, *real_path = NULL;
+
+    if ((name = strrchr(program_invocation_name, '/')))
+    {
+        real_path = realpath("/proc/self/exe", NULL);
+
+        /* Try to strip command line arguments. */
+        if (real_path && (p = strrchr(real_path, '/'))
+                && !strncmp(real_path, program_invocation_name, strlen(real_path)))
+        {
+            name = p;
+        }
+
+        ++name;
+    }
+    else if ((name = strrchr(program_invocation_name, '\\')))
+    {
+        ++name;
+    }
+    else
+    {
+        name = program_invocation_name;
+    }
+
+    strncpy(program_name, name, PATH_MAX);
+    program_name[PATH_MAX - 1] = '\0';
+    free(real_path);
+    return true;
+}
+
+#else
+
+bool vkd3d_get_program_name(char program_name[PATH_MAX])
+{
+    *program_name = '\0';
+    return false;
+}
+
+#endif  /* HAVE_DECL_PROGRAM_INVOCATION_NAME */
+
+static struct vkd3d_private_data *vkd3d_private_store_get_private_data(
+        const struct vkd3d_private_store *store, const GUID *tag)
+{
+    struct vkd3d_private_data *data;
+
+    LIST_FOR_EACH_ENTRY(data, &store->content, struct vkd3d_private_data, entry)
+    {
+        if (IsEqualGUID(&data->tag, tag))
+            return data;
+    }
+
+    return NULL;
+}
+
+static HRESULT vkd3d_private_store_set_private_data(struct vkd3d_private_store *store,
+        const GUID *tag, const void *data, unsigned int data_size, bool is_object)
+{
+    struct vkd3d_private_data *d, *old_data;
+    const void *ptr = data;
+
+    if (!data)
+    {
+        if ((d = vkd3d_private_store_get_private_data(store, tag)))
+        {
+            vkd3d_private_data_destroy(d);
+            return S_OK;
+        }
+
+        return S_FALSE;
+    }
+
+    if (is_object)
+    {
+        if (data_size != sizeof(IUnknown *))
+            return E_INVALIDARG;
+        ptr = &data;
+    }
+
+    if (!(d = vkd3d_malloc(offsetof(struct vkd3d_private_data, u.data[data_size]))))
+        return E_OUTOFMEMORY;
+
+    d->tag = *tag;
+    d->size = data_size;
+    d->is_object = is_object;
+    memcpy(d->u.data, ptr, data_size);
+    if (is_object)
+        IUnknown_AddRef(d->u.object);
+
+    if ((old_data = vkd3d_private_store_get_private_data(store, tag)))
+        vkd3d_private_data_destroy(old_data);
+    list_add_tail(&store->content, &d->entry);
+
+    return S_OK;
+}
+
+HRESULT vkd3d_get_private_data(struct vkd3d_private_store *store,
+        const GUID *tag, unsigned int *out_size, void *out)
+{
+    const struct vkd3d_private_data *data;
+    HRESULT hr = S_OK;
+    unsigned int size;
+    int rc;
+
+    if (!out_size)
+        return E_INVALIDARG;
+
+    if ((rc = pthread_mutex_lock(&store->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    if (!(data = vkd3d_private_store_get_private_data(store, tag)))
+    {
+        *out_size = 0;
+        hr = DXGI_ERROR_NOT_FOUND;
+        goto done;
+    }
+
+    size = *out_size;
+    *out_size = data->size;
+    if (!out)
+        goto done;
+
+    if (size < data->size)
+    {
+        hr = DXGI_ERROR_MORE_DATA;
+        goto done;
+    }
+
+    if (data->is_object)
+        IUnknown_AddRef(data->u.object);
+    memcpy(out, data->u.data, data->size);
+
+done:
+    pthread_mutex_unlock(&store->mutex);
+    return hr;
+}
+
+HRESULT vkd3d_set_private_data(struct vkd3d_private_store *store,
+        const GUID *tag, unsigned int data_size, const void *data)
+{
+    HRESULT hr;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&store->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    hr = vkd3d_private_store_set_private_data(store, tag, data, data_size, false);
+
+    pthread_mutex_unlock(&store->mutex);
+    return hr;
+}
+
+HRESULT vkd3d_set_private_data_interface(struct vkd3d_private_store *store,
+        const GUID *tag, const IUnknown *object)
+{
+    const void *data = object ? object : (void *)&object;
+    HRESULT hr;
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&store->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return hresult_from_errno(rc);
+    }
+
+    hr = vkd3d_private_store_set_private_data(store, tag, data, sizeof(object), !!object);
+
+    pthread_mutex_unlock(&store->mutex);
+    return hr;
+}
+
+VkResult vkd3d_set_vk_object_name_utf8(struct d3d12_device *device, uint64_t vk_object,
+        VkDebugReportObjectTypeEXT vk_object_type, const char *name)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    VkDebugMarkerObjectNameInfoEXT info;
+
+    if (!device->vk_info.EXT_debug_marker)
+        return VK_SUCCESS;
+
+    info.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
+    info.pNext = NULL;
+    info.objectType = vk_object_type;
+    info.object = vk_object;
+    info.pObjectName = name;
+    return VK_CALL(vkDebugMarkerSetObjectNameEXT(device->vk_device, &info));
+}
+
+HRESULT vkd3d_set_vk_object_name(struct d3d12_device *device, uint64_t vk_object,
+        VkDebugReportObjectTypeEXT vk_object_type, const WCHAR *name)
+{
+    char *name_utf8;
+    VkResult vr;
+
+    if (!name)
+        return E_INVALIDARG;
+
+    if (!device->vk_info.EXT_debug_marker)
+        return S_OK;
+
+    if (!(name_utf8 = vkd3d_strdup_w_utf8(name, device->wchar_size)))
+        return E_OUTOFMEMORY;
+
+    vr = vkd3d_set_vk_object_name_utf8(device, vk_object, vk_object_type, name_utf8);
+
+    vkd3d_free(name_utf8);
+
+    return hresult_from_vk_result(vr);
+}
diff --git a/dlls/vkd3d/libs/vkd3d/vkd3d.map b/dlls/vkd3d/libs/vkd3d/vkd3d.map
new file mode 100644
index 00000000000..6f1f376113e
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/vkd3d.map
@@ -0,0 +1,27 @@
+VKD3D_1_0
+{
+global:
+    vkd3d_acquire_vk_queue;
+    vkd3d_create_device;
+    vkd3d_create_image_resource;
+    vkd3d_create_instance;
+    vkd3d_create_root_signature_deserializer;
+    vkd3d_create_versioned_root_signature_deserializer;
+    vkd3d_get_device_parent;
+    vkd3d_get_dxgi_format;
+    vkd3d_get_vk_device;
+    vkd3d_get_vk_format;
+    vkd3d_get_vk_physical_device;
+    vkd3d_get_vk_queue_family_index;
+    vkd3d_instance_decref;
+    vkd3d_instance_from_device;
+    vkd3d_instance_get_vk_instance;
+    vkd3d_instance_incref;
+    vkd3d_release_vk_queue;
+    vkd3d_resource_decref;
+    vkd3d_resource_incref;
+    vkd3d_serialize_root_signature;
+    vkd3d_serialize_versioned_root_signature;
+
+local: *;
+};
diff --git a/dlls/vkd3d/libs/vkd3d/vkd3d_main.c b/dlls/vkd3d/libs/vkd3d/vkd3d_main.c
new file mode 100644
index 00000000000..327cdf882fa
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/vkd3d_main.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright 2016-2017 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define INITGUID
+#include "vkd3d_private.h"
+
+VKD3D_DEBUG_ENV_NAME("VKD3D_DEBUG");
+
+HRESULT vkd3d_create_device(const struct vkd3d_device_create_info *create_info,
+        REFIID iid, void **device)
+{
+    struct vkd3d_instance *instance;
+    struct d3d12_device *object;
+    HRESULT hr;
+
+    TRACE("create_info %p, iid %s, device %p.\n", create_info, debugstr_guid(iid), device);
+
+    if (!create_info)
+        return E_INVALIDARG;
+    if (create_info->type != VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO)
+    {
+        WARN("Invalid structure type %#x.\n", create_info->type);
+        return E_INVALIDARG;
+    }
+    if (!create_info->instance && !create_info->instance_create_info)
+    {
+        ERR("Instance or instance create info is required.\n");
+        return E_INVALIDARG;
+    }
+    if (create_info->instance && create_info->instance_create_info)
+    {
+        ERR("Instance and instance create info are mutually exclusive parameters.\n");
+        return E_INVALIDARG;
+    }
+
+    if (create_info->minimum_feature_level < D3D_FEATURE_LEVEL_11_0
+            || !is_valid_feature_level(create_info->minimum_feature_level))
+    {
+        WARN("Invalid feature level %#x.\n", create_info->minimum_feature_level);
+        return E_INVALIDARG;
+    }
+
+    if ((instance = create_info->instance))
+    {
+        vkd3d_instance_incref(instance);
+    }
+    else if (FAILED(hr = vkd3d_create_instance(create_info->instance_create_info, &instance)))
+    {
+        WARN("Failed to create instance, hr %#x.\n", hr);
+        return E_FAIL;
+    }
+
+    hr = d3d12_device_create(instance, create_info, &object);
+    vkd3d_instance_decref(instance);
+    if (FAILED(hr))
+        return hr;
+
+    if (!device)
+    {
+        ID3D12Device_Release(&object->ID3D12Device_iface);
+        return S_FALSE;
+    }
+
+    return return_interface(&object->ID3D12Device_iface, &IID_ID3D12Device, iid, device);
+}
+
+/* ID3D12RootSignatureDeserializer */
+struct d3d12_root_signature_deserializer
+{
+    ID3D12RootSignatureDeserializer ID3D12RootSignatureDeserializer_iface;
+    LONG refcount;
+
+    union
+    {
+        D3D12_VERSIONED_ROOT_SIGNATURE_DESC d3d12;
+        struct vkd3d_shader_versioned_root_signature_desc vkd3d;
+    } desc;
+};
+
+STATIC_ASSERT(sizeof(D3D12_ROOT_SIGNATURE_DESC) == sizeof(struct vkd3d_shader_root_signature_desc));
+
+static struct d3d12_root_signature_deserializer *impl_from_ID3D12RootSignatureDeserializer(
+        ID3D12RootSignatureDeserializer *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_root_signature_deserializer, ID3D12RootSignatureDeserializer_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_root_signature_deserializer_QueryInterface(
+        ID3D12RootSignatureDeserializer *iface, REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    /* QueryInterface() implementation is broken, E_NOINTERFACE is returned for
+     * IUnknown.
+     */
+    if (IsEqualGUID(riid, &IID_ID3D12RootSignatureDeserializer))
+    {
+        ID3D12RootSignatureDeserializer_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_root_signature_deserializer_AddRef(ID3D12RootSignatureDeserializer *iface)
+{
+    struct d3d12_root_signature_deserializer *deserializer = impl_from_ID3D12RootSignatureDeserializer(iface);
+    ULONG refcount = InterlockedIncrement(&deserializer->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", deserializer, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_root_signature_deserializer_Release(ID3D12RootSignatureDeserializer *iface)
+{
+    struct d3d12_root_signature_deserializer *deserializer = impl_from_ID3D12RootSignatureDeserializer(iface);
+    ULONG refcount = InterlockedDecrement(&deserializer->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", deserializer, refcount);
+
+    if (!refcount)
+    {
+        vkd3d_shader_free_root_signature(&deserializer->desc.vkd3d);
+        vkd3d_free(deserializer);
+    }
+
+    return refcount;
+}
+
+static const D3D12_ROOT_SIGNATURE_DESC * STDMETHODCALLTYPE d3d12_root_signature_deserializer_GetRootSignatureDesc(
+        ID3D12RootSignatureDeserializer *iface)
+{
+    struct d3d12_root_signature_deserializer *deserializer = impl_from_ID3D12RootSignatureDeserializer(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    assert(deserializer->desc.d3d12.Version == D3D_ROOT_SIGNATURE_VERSION_1_0);
+    return &deserializer->desc.d3d12.u.Desc_1_0;
+}
+
+static const struct ID3D12RootSignatureDeserializerVtbl d3d12_root_signature_deserializer_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_root_signature_deserializer_QueryInterface,
+    d3d12_root_signature_deserializer_AddRef,
+    d3d12_root_signature_deserializer_Release,
+    /* ID3D12RootSignatureDeserializer methods */
+    d3d12_root_signature_deserializer_GetRootSignatureDesc,
+};
+
+int vkd3d_parse_root_signature_v_1_0(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_versioned_root_signature_desc *out_desc)
+{
+    struct vkd3d_shader_versioned_root_signature_desc desc, converted_desc;
+    int ret;
+
+    if ((ret = vkd3d_shader_parse_root_signature(dxbc, &desc, NULL)) < 0)
+    {
+        WARN("Failed to parse root signature, vkd3d result %d.\n", ret);
+        return ret;
+    }
+
+    if (desc.version == VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0)
+    {
+        *out_desc = desc;
+    }
+    else
+    {
+        enum vkd3d_shader_root_signature_version version = desc.version;
+
+        ret = vkd3d_shader_convert_root_signature(&converted_desc, VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0, &desc);
+        vkd3d_shader_free_root_signature(&desc);
+        if (ret < 0)
+        {
+            WARN("Failed to convert from version %#x, vkd3d result %d.\n", version, ret);
+            return ret;
+        }
+
+        *out_desc = converted_desc;
+    }
+
+    return ret;
+}
+
+static HRESULT d3d12_root_signature_deserializer_init(struct d3d12_root_signature_deserializer *deserializer,
+        const struct vkd3d_shader_code *dxbc)
+{
+    int ret;
+
+    deserializer->ID3D12RootSignatureDeserializer_iface.lpVtbl = &d3d12_root_signature_deserializer_vtbl;
+    deserializer->refcount = 1;
+
+    if ((ret = vkd3d_parse_root_signature_v_1_0(dxbc, &deserializer->desc.vkd3d)) < 0)
+        return hresult_from_vkd3d_result(ret);
+
+    return S_OK;
+}
+
+HRESULT vkd3d_create_root_signature_deserializer(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer)
+{
+    struct vkd3d_shader_code dxbc = {data, data_size};
+    struct d3d12_root_signature_deserializer *object;
+    HRESULT hr;
+
+    TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
+            data, data_size, debugstr_guid(iid), deserializer);
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_root_signature_deserializer_init(object, &dxbc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    return return_interface(&object->ID3D12RootSignatureDeserializer_iface,
+            &IID_ID3D12RootSignatureDeserializer, iid, deserializer);
+}
+
+/* ID3D12VersionedRootSignatureDeserializer */
+struct d3d12_versioned_root_signature_deserializer
+{
+    ID3D12VersionedRootSignatureDeserializer ID3D12VersionedRootSignatureDeserializer_iface;
+    LONG refcount;
+
+    union
+    {
+        D3D12_VERSIONED_ROOT_SIGNATURE_DESC d3d12;
+        struct vkd3d_shader_versioned_root_signature_desc vkd3d;
+    } desc, other_desc;
+};
+
+STATIC_ASSERT(sizeof(D3D12_VERSIONED_ROOT_SIGNATURE_DESC) == sizeof(struct vkd3d_shader_versioned_root_signature_desc));
+
+static struct d3d12_versioned_root_signature_deserializer *impl_from_ID3D12VersionedRootSignatureDeserializer(
+        ID3D12VersionedRootSignatureDeserializer *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d12_versioned_root_signature_deserializer,
+            ID3D12VersionedRootSignatureDeserializer_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_QueryInterface(
+        ID3D12VersionedRootSignatureDeserializer *iface, REFIID iid, void **object)
+{
+    TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
+
+    /* QueryInterface() implementation is broken, E_NOINTERFACE is returned for
+     * IUnknown.
+     */
+    if (IsEqualGUID(iid, &IID_ID3D12VersionedRootSignatureDeserializer))
+    {
+        ID3D12VersionedRootSignatureDeserializer_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_AddRef(ID3D12VersionedRootSignatureDeserializer *iface)
+{
+    struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
+    ULONG refcount = InterlockedIncrement(&deserializer->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", deserializer, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_Release(ID3D12VersionedRootSignatureDeserializer *iface)
+{
+    struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
+    ULONG refcount = InterlockedDecrement(&deserializer->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", deserializer, refcount);
+
+    if (!refcount)
+    {
+        vkd3d_shader_free_root_signature(&deserializer->desc.vkd3d);
+        vkd3d_shader_free_root_signature(&deserializer->other_desc.vkd3d);
+        vkd3d_free(deserializer);
+    }
+
+    return refcount;
+}
+
+static enum vkd3d_shader_root_signature_version vkd3d_root_signature_version_from_d3d12(
+        D3D_ROOT_SIGNATURE_VERSION version)
+{
+    switch (version)
+    {
+        case D3D_ROOT_SIGNATURE_VERSION_1_0:
+            return VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0;
+        case D3D_ROOT_SIGNATURE_VERSION_1_1:
+            return VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_1;
+        default:
+            WARN("Unknown root signature version %#x.\n", version);
+            return 0;
+    }
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_GetRootSignatureDescAtVersion(
+        ID3D12VersionedRootSignatureDeserializer *iface, D3D_ROOT_SIGNATURE_VERSION version,
+        const D3D12_VERSIONED_ROOT_SIGNATURE_DESC **desc)
+{
+    struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
+    int ret;
+
+    TRACE("iface %p, version %#x, desc %p.\n", iface, version, desc);
+
+    if (version != D3D_ROOT_SIGNATURE_VERSION_1_0 && version != D3D_ROOT_SIGNATURE_VERSION_1_1)
+    {
+        WARN("Root signature version %#x not supported.\n", version);
+        return E_INVALIDARG;
+    }
+
+    if (deserializer->desc.d3d12.Version == version)
+    {
+        *desc = &deserializer->desc.d3d12;
+        return S_OK;
+    }
+
+    if (!deserializer->other_desc.d3d12.Version)
+    {
+        if ((ret = vkd3d_shader_convert_root_signature(&deserializer->other_desc.vkd3d,
+                vkd3d_root_signature_version_from_d3d12(version), &deserializer->desc.vkd3d)) < 0)
+        {
+            WARN("Failed to convert versioned root signature, vkd3d result %d.\n", ret);
+            return hresult_from_vkd3d_result(ret);
+        }
+    }
+
+    assert(deserializer->other_desc.d3d12.Version == version);
+    *desc = &deserializer->other_desc.d3d12;
+    return S_OK;
+}
+
+static const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * STDMETHODCALLTYPE
+d3d12_versioned_root_signature_deserializer_GetUnconvertedRootSignatureDesc(ID3D12VersionedRootSignatureDeserializer *iface)
+{
+    struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return &deserializer->desc.d3d12;
+}
+
+static const struct ID3D12VersionedRootSignatureDeserializerVtbl d3d12_versioned_root_signature_deserializer_vtbl =
+{
+    /* IUnknown methods */
+    d3d12_versioned_root_signature_deserializer_QueryInterface,
+    d3d12_versioned_root_signature_deserializer_AddRef,
+    d3d12_versioned_root_signature_deserializer_Release,
+    /* ID3D12VersionedRootSignatureDeserializer methods */
+    d3d12_versioned_root_signature_deserializer_GetRootSignatureDescAtVersion,
+    d3d12_versioned_root_signature_deserializer_GetUnconvertedRootSignatureDesc,
+};
+
+static HRESULT d3d12_versioned_root_signature_deserializer_init(struct d3d12_versioned_root_signature_deserializer *deserializer,
+        const struct vkd3d_shader_code *dxbc)
+{
+    int ret;
+
+    deserializer->ID3D12VersionedRootSignatureDeserializer_iface.lpVtbl = &d3d12_versioned_root_signature_deserializer_vtbl;
+    deserializer->refcount = 1;
+
+    if ((ret = vkd3d_shader_parse_root_signature(dxbc, &deserializer->desc.vkd3d, NULL)) < 0)
+    {
+        WARN("Failed to parse root signature, vkd3d result %d.\n", ret);
+        return hresult_from_vkd3d_result(ret);
+    }
+
+    memset(&deserializer->other_desc, 0, sizeof(deserializer->other_desc));
+
+    return S_OK;
+}
+
+HRESULT vkd3d_create_versioned_root_signature_deserializer(const void *data, SIZE_T data_size,
+        REFIID iid, void **deserializer)
+{
+    struct d3d12_versioned_root_signature_deserializer *object;
+    struct vkd3d_shader_code dxbc = {data, data_size};
+    HRESULT hr;
+
+    TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
+            data, data_size, debugstr_guid(iid), deserializer);
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = d3d12_versioned_root_signature_deserializer_init(object, &dxbc)))
+    {
+        vkd3d_free(object);
+        return hr;
+    }
+
+    return return_interface(&object->ID3D12VersionedRootSignatureDeserializer_iface,
+            &IID_ID3D12VersionedRootSignatureDeserializer, iid, deserializer);
+}
+
+/* ID3DBlob */
+struct d3d_blob
+{
+    ID3D10Blob ID3DBlob_iface;
+    LONG refcount;
+
+    void *buffer;
+    SIZE_T size;
+};
+
+static struct d3d_blob *impl_from_ID3DBlob(ID3DBlob *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d_blob, ID3DBlob_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d_blob_QueryInterface(ID3DBlob *iface, REFIID riid, void **object)
+{
+    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+    if (IsEqualGUID(riid, &IID_ID3DBlob)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        ID3D10Blob_AddRef(iface);
+        *object = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *object = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d3d_blob_AddRef(ID3DBlob *iface)
+{
+    struct d3d_blob *blob = impl_from_ID3DBlob(iface);
+    ULONG refcount = InterlockedIncrement(&blob->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", blob, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d_blob_Release(ID3DBlob *iface)
+{
+    struct d3d_blob *blob = impl_from_ID3DBlob(iface);
+    ULONG refcount = InterlockedDecrement(&blob->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", blob, refcount);
+
+    if (!refcount)
+    {
+        vkd3d_free(blob->buffer);
+
+        vkd3d_free(blob);
+    }
+
+    return refcount;
+}
+
+static void * STDMETHODCALLTYPE d3d_blob_GetBufferPointer(ID3DBlob *iface)
+{
+    struct d3d_blob *blob = impl_from_ID3DBlob(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return blob->buffer;
+}
+
+static SIZE_T STDMETHODCALLTYPE d3d_blob_GetBufferSize(ID3DBlob *iface)
+{
+    struct d3d_blob *blob = impl_from_ID3DBlob(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return blob->size;
+}
+
+static const struct ID3D10BlobVtbl d3d_blob_vtbl =
+{
+    /* IUnknown methods */
+    d3d_blob_QueryInterface,
+    d3d_blob_AddRef,
+    d3d_blob_Release,
+    /* ID3DBlob methods */
+    d3d_blob_GetBufferPointer,
+    d3d_blob_GetBufferSize
+};
+
+static void d3d_blob_init(struct d3d_blob *blob, void *buffer, SIZE_T size)
+{
+    blob->ID3DBlob_iface.lpVtbl = &d3d_blob_vtbl;
+    blob->refcount = 1;
+
+    blob->buffer = buffer;
+    blob->size = size;
+}
+
+static HRESULT d3d_blob_create(void *buffer, SIZE_T size, struct d3d_blob **blob)
+{
+    struct d3d_blob *object;
+
+    if (!(object = vkd3d_malloc(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    d3d_blob_init(object, buffer, size);
+
+    TRACE("Created blob object %p.\n", object);
+
+    *blob = object;
+
+    return S_OK;
+}
+
+HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *desc,
+        D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob)
+{
+    struct vkd3d_shader_versioned_root_signature_desc vkd3d_desc;
+    struct vkd3d_shader_code dxbc;
+    struct d3d_blob *blob_object;
+    char *messages;
+    HRESULT hr;
+    int ret;
+
+    TRACE("desc %p, version %#x, blob %p, error_blob %p.\n", desc, version, blob, error_blob);
+
+    if (version != D3D_ROOT_SIGNATURE_VERSION_1_0)
+    {
+        WARN("Unexpected Root signature version %#x.\n", version);
+        return E_INVALIDARG;
+    }
+
+    if (!blob)
+    {
+        WARN("Invalid blob parameter.\n");
+        return E_INVALIDARG;
+    }
+
+    if (error_blob)
+        *error_blob = NULL;
+
+    vkd3d_desc.version = VKD3D_SHADER_ROOT_SIGNATURE_VERSION_1_0;
+    vkd3d_desc.u.v_1_0 = *(const struct vkd3d_shader_root_signature_desc *)desc;
+    if ((ret = vkd3d_shader_serialize_root_signature(&vkd3d_desc, &dxbc, &messages)) < 0)
+    {
+        WARN("Failed to serialize root signature, vkd3d result %d.\n", ret);
+        if (error_blob && messages)
+        {
+            if (FAILED(hr = d3d_blob_create(messages, strlen(messages), &blob_object)))
+                ERR("Failed to create error blob, hr %#x.\n", hr);
+            else
+                *error_blob = &blob_object->ID3DBlob_iface;
+        }
+        return hresult_from_vkd3d_result(ret);
+    }
+    vkd3d_shader_free_messages(messages);
+
+    if (FAILED(hr = d3d_blob_create((void *)dxbc.code, dxbc.size, &blob_object)))
+    {
+        WARN("Failed to create blob object, hr %#x.\n", hr);
+        vkd3d_shader_free_shader_code(&dxbc);
+        return hr;
+    }
+
+    *blob = &blob_object->ID3DBlob_iface;
+
+    return S_OK;
+}
+
+HRESULT vkd3d_serialize_versioned_root_signature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+        ID3DBlob **blob, ID3DBlob **error_blob)
+{
+    const struct vkd3d_shader_versioned_root_signature_desc *vkd3d_desc;
+    struct vkd3d_shader_code dxbc;
+    struct d3d_blob *blob_object;
+    char *messages;
+    HRESULT hr;
+    int ret;
+
+    TRACE("desc %p, blob %p, error_blob %p.\n", desc, blob, error_blob);
+
+    if (!blob)
+    {
+        WARN("Invalid blob parameter.\n");
+        return E_INVALIDARG;
+    }
+
+    if (error_blob)
+        *error_blob = NULL;
+
+    vkd3d_desc = (const struct vkd3d_shader_versioned_root_signature_desc *)desc;
+    if ((ret = vkd3d_shader_serialize_root_signature(vkd3d_desc, &dxbc, &messages)) < 0)
+    {
+        WARN("Failed to serialize root signature, vkd3d result %d.\n", ret);
+        if (error_blob && messages)
+        {
+            if (FAILED(hr = d3d_blob_create(messages, strlen(messages), &blob_object)))
+                ERR("Failed to create error blob, hr %#x.\n", hr);
+            else
+                *error_blob = &blob_object->ID3DBlob_iface;
+        }
+        return hresult_from_vkd3d_result(ret);
+    }
+    vkd3d_shader_free_messages(messages);
+
+    if (FAILED(hr = d3d_blob_create((void *)dxbc.code, dxbc.size, &blob_object)))
+    {
+        WARN("Failed to create blob object, hr %#x.\n", hr);
+        vkd3d_shader_free_shader_code(&dxbc);
+        return hr;
+    }
+
+    *blob = &blob_object->ID3DBlob_iface;
+
+    return S_OK;
+}
diff --git a/dlls/vkd3d/libs/vkd3d/vkd3d_private.h b/dlls/vkd3d/libs/vkd3d/vkd3d_private.h
new file mode 100644
index 00000000000..9f0982df05f
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/vkd3d_private.h
@@ -0,0 +1,1372 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_PRIVATE_H
+#define __VKD3D_PRIVATE_H
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define VK_NO_PROTOTYPES
+
+#include "vkd3d_common.h"
+#include "vkd3d_memory.h"
+#include "vkd3d_utf8.h"
+#include "list.h"
+#include "rbtree.h"
+
+#include "vkd3d.h"
+#include "vkd3d_shader.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#define VK_CALL(f) (vk_procs->f)
+
+#define VKD3D_DESCRIPTOR_MAGIC_FREE    0x00000000u
+#define VKD3D_DESCRIPTOR_MAGIC_CBV     0x00564243u
+#define VKD3D_DESCRIPTOR_MAGIC_SRV     0x00565253u
+#define VKD3D_DESCRIPTOR_MAGIC_UAV     0x00564155u
+#define VKD3D_DESCRIPTOR_MAGIC_SAMPLER 0x504d4153u
+#define VKD3D_DESCRIPTOR_MAGIC_DSV     0x00565344u
+#define VKD3D_DESCRIPTOR_MAGIC_RTV     0x00565452u
+
+#define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u
+#define VKD3D_MAX_QUEUE_FAMILY_COUNT      3u
+#define VKD3D_MAX_SHADER_EXTENSIONS       1u
+#define VKD3D_MAX_SHADER_STAGES           5u
+#define VKD3D_MAX_VK_SYNC_OBJECTS         4u
+
+struct d3d12_command_list;
+struct d3d12_device;
+struct d3d12_resource;
+
+struct vkd3d_vk_global_procs
+{
+    PFN_vkCreateInstance vkCreateInstance;
+    PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
+    PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
+};
+
+#define DECLARE_VK_PFN(name) PFN_##name name;
+struct vkd3d_vk_instance_procs
+{
+#define VK_INSTANCE_PFN     DECLARE_VK_PFN
+#define VK_INSTANCE_EXT_PFN DECLARE_VK_PFN
+#include "vulkan_procs.h"
+};
+
+struct vkd3d_vk_device_procs
+{
+#define VK_INSTANCE_PFN   DECLARE_VK_PFN
+#define VK_DEVICE_PFN     DECLARE_VK_PFN
+#define VK_DEVICE_EXT_PFN DECLARE_VK_PFN
+#include "vulkan_procs.h"
+};
+#undef DECLARE_VK_PFN
+
+HRESULT hresult_from_errno(int rc) DECLSPEC_HIDDEN;
+HRESULT hresult_from_vk_result(VkResult vr) DECLSPEC_HIDDEN;
+HRESULT hresult_from_vkd3d_result(int vkd3d_result) DECLSPEC_HIDDEN;
+
+struct vkd3d_vulkan_info
+{
+    /* KHR instance extensions */
+    bool KHR_get_physical_device_properties2;
+    /* EXT instance extensions */
+    bool EXT_debug_report;
+
+    /* KHR device extensions */
+    bool KHR_dedicated_allocation;
+    bool KHR_draw_indirect_count;
+    bool KHR_get_memory_requirements2;
+    bool KHR_image_format_list;
+    bool KHR_maintenance3;
+    bool KHR_push_descriptor;
+    /* EXT device extensions */
+    bool EXT_conditional_rendering;
+    bool EXT_debug_marker;
+    bool EXT_depth_clip_enable;
+    bool EXT_descriptor_indexing;
+    bool EXT_shader_demote_to_helper_invocation;
+    bool EXT_texel_buffer_alignment;
+    bool EXT_transform_feedback;
+    bool EXT_vertex_attribute_divisor;
+
+    bool rasterization_stream;
+    bool transform_feedback_queries;
+
+    bool vertex_attrib_zero_divisor;
+    unsigned int max_vertex_attrib_divisor;
+
+    VkPhysicalDeviceLimits device_limits;
+    VkPhysicalDeviceSparseProperties sparse_properties;
+
+    VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties;
+
+    unsigned int shader_extension_count;
+    enum vkd3d_shader_spirv_extension shader_extensions[VKD3D_MAX_SHADER_EXTENSIONS];
+
+    D3D_FEATURE_LEVEL max_feature_level;
+};
+
+enum vkd3d_config_flags
+{
+    VKD3D_CONFIG_FLAG_VULKAN_DEBUG = 0x00000001,
+};
+
+struct vkd3d_instance
+{
+    VkInstance vk_instance;
+    struct vkd3d_vk_instance_procs vk_procs;
+
+    PFN_vkd3d_signal_event signal_event;
+    PFN_vkd3d_create_thread create_thread;
+    PFN_vkd3d_join_thread join_thread;
+    size_t wchar_size;
+
+    struct vkd3d_vulkan_info vk_info;
+    struct vkd3d_vk_global_procs vk_global_procs;
+    void *libvulkan;
+
+    uint64_t config_flags;
+    enum vkd3d_api_version api_version;
+
+    VkDebugReportCallbackEXT vk_debug_callback;
+
+    LONG refcount;
+};
+
+union vkd3d_thread_handle
+{
+    pthread_t pthread;
+    void *handle;
+};
+
+HRESULT vkd3d_create_thread(struct vkd3d_instance *instance,
+        PFN_vkd3d_thread thread_main, void *data, union vkd3d_thread_handle *thread) DECLSPEC_HIDDEN;
+HRESULT vkd3d_join_thread(struct vkd3d_instance *instance, union vkd3d_thread_handle *thread) DECLSPEC_HIDDEN;
+
+struct vkd3d_waiting_fence
+{
+    struct d3d12_fence *fence;
+    uint64_t value;
+    struct vkd3d_queue *queue;
+    uint64_t queue_sequence_number;
+};
+
+struct vkd3d_fence_worker
+{
+    union vkd3d_thread_handle thread;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_cond_t fence_destruction_cond;
+    bool should_exit;
+    bool pending_fence_destruction;
+
+    size_t enqueued_fence_count;
+    struct vkd3d_enqueued_fence
+    {
+        VkFence vk_fence;
+        struct vkd3d_waiting_fence waiting_fence;
+    } *enqueued_fences;
+    size_t enqueued_fences_size;
+
+    size_t fence_count;
+    VkFence *vk_fences;
+    size_t vk_fences_size;
+    struct vkd3d_waiting_fence *fences;
+    size_t fences_size;
+
+    struct d3d12_device *device;
+};
+
+HRESULT vkd3d_fence_worker_start(struct vkd3d_fence_worker *worker,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+HRESULT vkd3d_fence_worker_stop(struct vkd3d_fence_worker *worker,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+struct vkd3d_gpu_va_allocation
+{
+    D3D12_GPU_VIRTUAL_ADDRESS base;
+    size_t size;
+    void *ptr;
+};
+
+struct vkd3d_gpu_va_slab
+{
+    size_t size;
+    void *ptr;
+};
+
+struct vkd3d_gpu_va_allocator
+{
+    pthread_mutex_t mutex;
+
+    D3D12_GPU_VIRTUAL_ADDRESS fallback_floor;
+    struct vkd3d_gpu_va_allocation *fallback_allocations;
+    size_t fallback_allocations_size;
+    size_t fallback_allocation_count;
+
+    struct vkd3d_gpu_va_slab *slabs;
+    struct vkd3d_gpu_va_slab *free_slab;
+};
+
+D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
+        size_t alignment, size_t size, void *ptr) DECLSPEC_HIDDEN;
+void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address) DECLSPEC_HIDDEN;
+void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator,
+        D3D12_GPU_VIRTUAL_ADDRESS address) DECLSPEC_HIDDEN;
+
+struct vkd3d_render_pass_key
+{
+    unsigned int attachment_count;
+    bool depth_enable;
+    bool stencil_enable;
+    bool depth_stencil_write;
+    bool padding;
+    unsigned int sample_count;
+    VkFormat vk_formats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
+};
+
+struct vkd3d_render_pass_entry;
+
+struct vkd3d_render_pass_cache
+{
+    struct vkd3d_render_pass_entry *render_passes;
+    size_t render_pass_count;
+    size_t render_passes_size;
+};
+
+void vkd3d_render_pass_cache_cleanup(struct vkd3d_render_pass_cache *cache,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+HRESULT vkd3d_render_pass_cache_find(struct vkd3d_render_pass_cache *cache,
+        struct d3d12_device *device, const struct vkd3d_render_pass_key *key,
+        VkRenderPass *vk_render_pass) DECLSPEC_HIDDEN;
+void vkd3d_render_pass_cache_init(struct vkd3d_render_pass_cache *cache) DECLSPEC_HIDDEN;
+
+struct vkd3d_private_store
+{
+    pthread_mutex_t mutex;
+
+    struct list content;
+};
+
+struct vkd3d_private_data
+{
+    struct list entry;
+
+    GUID tag;
+    unsigned int size;
+    bool is_object;
+    union
+    {
+        BYTE data[1];
+        IUnknown *object;
+    } u;
+};
+
+static inline void vkd3d_private_data_destroy(struct vkd3d_private_data *data)
+{
+    if (data->is_object)
+        IUnknown_Release(data->u.object);
+    list_remove(&data->entry);
+    vkd3d_free(data);
+}
+
+static inline HRESULT vkd3d_private_store_init(struct vkd3d_private_store *store)
+{
+    int rc;
+
+    list_init(&store->content);
+
+    if ((rc = pthread_mutex_init(&store->mutex, NULL)))
+        ERR("Failed to initialize mutex, error %d.\n", rc);
+
+    return hresult_from_errno(rc);
+}
+
+static inline void vkd3d_private_store_destroy(struct vkd3d_private_store *store)
+{
+    struct vkd3d_private_data *data, *cursor;
+
+    LIST_FOR_EACH_ENTRY_SAFE(data, cursor, &store->content, struct vkd3d_private_data, entry)
+    {
+        vkd3d_private_data_destroy(data);
+    }
+
+    pthread_mutex_destroy(&store->mutex);
+}
+
+HRESULT vkd3d_get_private_data(struct vkd3d_private_store *store,
+        const GUID *tag, unsigned int *out_size, void *out) DECLSPEC_HIDDEN;
+HRESULT vkd3d_set_private_data(struct vkd3d_private_store *store,
+        const GUID *tag, unsigned int data_size, const void *data) DECLSPEC_HIDDEN;
+HRESULT vkd3d_set_private_data_interface(struct vkd3d_private_store *store,
+        const GUID *tag, const IUnknown *object) DECLSPEC_HIDDEN;
+
+struct vkd3d_signaled_semaphore
+{
+    struct list entry;
+    uint64_t value;
+    VkSemaphore vk_semaphore;
+    VkFence vk_fence;
+    bool is_acquired;
+};
+
+/* ID3D12Fence */
+struct d3d12_fence
+{
+    ID3D12Fence ID3D12Fence_iface;
+    LONG refcount;
+
+    uint64_t value;
+    pthread_mutex_t mutex;
+
+    struct vkd3d_waiting_event
+    {
+        uint64_t value;
+        HANDLE event;
+    } *events;
+    size_t events_size;
+    size_t event_count;
+
+    struct list semaphores;
+    unsigned int semaphore_count;
+
+    LONG pending_worker_operation_count;
+
+    VkFence old_vk_fences[VKD3D_MAX_VK_SYNC_OBJECTS];
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_fence_create(struct d3d12_device *device,
+        uint64_t initial_value, D3D12_FENCE_FLAGS flags, struct d3d12_fence **fence) DECLSPEC_HIDDEN;
+
+/* ID3D12Heap */
+struct d3d12_heap
+{
+    ID3D12Heap ID3D12Heap_iface;
+    LONG refcount;
+
+    bool is_private;
+    D3D12_HEAP_DESC desc;
+
+    pthread_mutex_t mutex;
+
+    VkDeviceMemory vk_memory;
+    void *map_ptr;
+    unsigned int map_count;
+    uint32_t vk_memory_type;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_heap_create(struct d3d12_device *device, const D3D12_HEAP_DESC *desc,
+        const struct d3d12_resource *resource, struct d3d12_heap **heap) DECLSPEC_HIDDEN;
+struct d3d12_heap *unsafe_impl_from_ID3D12Heap(ID3D12Heap *iface) DECLSPEC_HIDDEN;
+
+#define VKD3D_RESOURCE_PUBLIC_FLAGS \
+        (VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION)
+#define VKD3D_RESOURCE_EXTERNAL       0x00000004
+#define VKD3D_RESOURCE_DEDICATED_HEAP 0x00000008
+#define VKD3D_RESOURCE_LINEAR_TILING  0x00000010
+
+/* ID3D12Resource */
+struct d3d12_resource
+{
+    ID3D12Resource ID3D12Resource_iface;
+    LONG refcount;
+    LONG internal_refcount;
+
+    D3D12_RESOURCE_DESC desc;
+
+    D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
+    union
+    {
+        VkBuffer vk_buffer;
+        VkImage vk_image;
+    } u;
+    unsigned int flags;
+
+    unsigned int map_count;
+
+    struct d3d12_heap *heap;
+    uint64_t heap_offset;
+
+    D3D12_RESOURCE_STATES initial_state;
+    D3D12_RESOURCE_STATES present_state;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+static inline bool d3d12_resource_is_buffer(const struct d3d12_resource *resource)
+{
+    return resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER;
+}
+
+static inline bool d3d12_resource_is_texture(const struct d3d12_resource *resource)
+{
+    return resource->desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER;
+}
+
+bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource) DECLSPEC_HIDDEN;
+HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+HRESULT d3d12_committed_resource_create(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) DECLSPEC_HIDDEN;
+HRESULT d3d12_placed_resource_create(struct d3d12_device *device, struct d3d12_heap *heap, uint64_t heap_offset,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) DECLSPEC_HIDDEN;
+HRESULT d3d12_reserved_resource_create(struct d3d12_device *device,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
+        const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) DECLSPEC_HIDDEN;
+struct d3d12_resource *unsafe_impl_from_ID3D12Resource(ID3D12Resource *iface) DECLSPEC_HIDDEN;
+
+HRESULT vkd3d_allocate_buffer_memory(struct d3d12_device *device, VkBuffer vk_buffer,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        VkDeviceMemory *vk_memory, uint32_t *vk_memory_type, VkDeviceSize *vk_memory_size) DECLSPEC_HIDDEN;
+HRESULT vkd3d_create_buffer(struct d3d12_device *device,
+        const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
+        const D3D12_RESOURCE_DESC *desc, VkBuffer *vk_buffer) DECLSPEC_HIDDEN;
+HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
+        const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info) DECLSPEC_HIDDEN;
+
+enum vkd3d_view_type
+{
+    VKD3D_VIEW_TYPE_BUFFER,
+    VKD3D_VIEW_TYPE_IMAGE,
+    VKD3D_VIEW_TYPE_SAMPLER,
+};
+
+struct vkd3d_view
+{
+    LONG refcount;
+    enum vkd3d_view_type type;
+    union
+    {
+        VkBufferView vk_buffer_view;
+        VkImageView vk_image_view;
+        VkSampler vk_sampler;
+    } u;
+    VkBufferView vk_counter_view;
+    const struct vkd3d_format *format;
+    union
+    {
+        struct
+        {
+            VkDeviceSize offset;
+            VkDeviceSize size;
+        } buffer;
+        struct
+        {
+            VkImageViewType vk_view_type;
+            unsigned int miplevel_idx;
+            unsigned int layer_idx;
+            unsigned int layer_count;
+        } texture;
+    } info;
+};
+
+void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device) DECLSPEC_HIDDEN;
+void vkd3d_view_incref(struct vkd3d_view *view) DECLSPEC_HIDDEN;
+
+struct vkd3d_texture_view_desc
+{
+    VkImageViewType view_type;
+    const struct vkd3d_format *format;
+    unsigned int miplevel_idx;
+    unsigned int miplevel_count;
+    unsigned int layer_idx;
+    unsigned int layer_count;
+    VkComponentMapping components;
+    bool allowed_swizzle;
+};
+
+bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, const struct vkd3d_format *format,
+        VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view) DECLSPEC_HIDDEN;
+bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image,
+        const struct vkd3d_texture_view_desc *desc, struct vkd3d_view **view) DECLSPEC_HIDDEN;
+
+struct d3d12_desc
+{
+    uint32_t magic;
+    VkDescriptorType vk_descriptor_type;
+    union
+    {
+        VkDescriptorBufferInfo vk_cbv_info;
+        struct vkd3d_view *view;
+    } u;
+};
+
+static inline struct d3d12_desc *d3d12_desc_from_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
+{
+    return (struct d3d12_desc *)cpu_handle.ptr;
+}
+
+static inline struct d3d12_desc *d3d12_desc_from_gpu_handle(D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle)
+{
+    return (struct d3d12_desc *)(intptr_t)gpu_handle.ptr;
+}
+
+void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+void d3d12_desc_create_cbv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc) DECLSPEC_HIDDEN;
+void d3d12_desc_create_srv(struct d3d12_desc *descriptor,
+        struct d3d12_device *device, struct d3d12_resource *resource,
+        const D3D12_SHADER_RESOURCE_VIEW_DESC *desc) DECLSPEC_HIDDEN;
+void d3d12_desc_create_uav(struct d3d12_desc *descriptor, struct d3d12_device *device,
+        struct d3d12_resource *resource, struct d3d12_resource *counter_resource,
+        const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc) DECLSPEC_HIDDEN;
+void d3d12_desc_create_sampler(struct d3d12_desc *sampler,
+        struct d3d12_device *device, const D3D12_SAMPLER_DESC *desc) DECLSPEC_HIDDEN;
+void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+bool vkd3d_create_raw_buffer_view(struct d3d12_device *device,
+        D3D12_GPU_VIRTUAL_ADDRESS gpu_address, VkBufferView *vk_buffer_view) DECLSPEC_HIDDEN;
+HRESULT vkd3d_create_static_sampler(struct d3d12_device *device,
+        const D3D12_STATIC_SAMPLER_DESC *desc, VkSampler *vk_sampler) DECLSPEC_HIDDEN;
+
+struct d3d12_rtv_desc
+{
+    uint32_t magic;
+    VkSampleCountFlagBits sample_count;
+    const struct vkd3d_format *format;
+    uint64_t width;
+    unsigned int height;
+    unsigned int layer_count;
+    struct vkd3d_view *view;
+    struct d3d12_resource *resource;
+};
+
+static inline struct d3d12_rtv_desc *d3d12_rtv_desc_from_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
+{
+    return (struct d3d12_rtv_desc *)cpu_handle.ptr;
+}
+
+void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_device *device,
+        struct d3d12_resource *resource, const D3D12_RENDER_TARGET_VIEW_DESC *desc) DECLSPEC_HIDDEN;
+
+struct d3d12_dsv_desc
+{
+    uint32_t magic;
+    VkSampleCountFlagBits sample_count;
+    const struct vkd3d_format *format;
+    uint64_t width;
+    unsigned int height;
+    unsigned int layer_count;
+    struct vkd3d_view *view;
+    struct d3d12_resource *resource;
+};
+
+static inline struct d3d12_dsv_desc *d3d12_dsv_desc_from_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
+{
+    return (struct d3d12_dsv_desc *)cpu_handle.ptr;
+}
+
+void d3d12_dsv_desc_create_dsv(struct d3d12_dsv_desc *dsv_desc, struct d3d12_device *device,
+        struct d3d12_resource *resource, const D3D12_DEPTH_STENCIL_VIEW_DESC *desc) DECLSPEC_HIDDEN;
+
+/* ID3D12DescriptorHeap */
+struct d3d12_descriptor_heap
+{
+    ID3D12DescriptorHeap ID3D12DescriptorHeap_iface;
+    LONG refcount;
+
+    D3D12_DESCRIPTOR_HEAP_DESC desc;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+
+    BYTE descriptors[];
+};
+
+HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
+        const D3D12_DESCRIPTOR_HEAP_DESC *desc, struct d3d12_descriptor_heap **descriptor_heap) DECLSPEC_HIDDEN;
+
+/* ID3D12QueryHeap */
+struct d3d12_query_heap
+{
+    ID3D12QueryHeap ID3D12QueryHeap_iface;
+    LONG refcount;
+
+    VkQueryPool vk_query_pool;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+
+    uint64_t availability_mask[];
+};
+
+HRESULT d3d12_query_heap_create(struct d3d12_device *device, const D3D12_QUERY_HEAP_DESC *desc,
+        struct d3d12_query_heap **heap) DECLSPEC_HIDDEN;
+struct d3d12_query_heap *unsafe_impl_from_ID3D12QueryHeap(ID3D12QueryHeap *iface) DECLSPEC_HIDDEN;
+
+/* A Vulkan query has to be issued at least one time before the result is
+ * available. In D3D12 it is legal to get query reults for not issued queries.
+ */
+static inline bool d3d12_query_heap_is_result_available(const struct d3d12_query_heap *heap,
+        unsigned int query_index)
+{
+    unsigned int index = query_index / (sizeof(*heap->availability_mask) * CHAR_BIT);
+    unsigned int shift = query_index % (sizeof(*heap->availability_mask) * CHAR_BIT);
+    return heap->availability_mask[index] & ((uint64_t)1 << shift);
+}
+
+static inline void d3d12_query_heap_mark_result_as_available(struct d3d12_query_heap *heap,
+        unsigned int query_index)
+{
+    unsigned int index = query_index / (sizeof(*heap->availability_mask) * CHAR_BIT);
+    unsigned int shift = query_index % (sizeof(*heap->availability_mask) * CHAR_BIT);
+    heap->availability_mask[index] |= (uint64_t)1 << shift;
+}
+
+struct d3d12_root_descriptor_table_range
+{
+    unsigned int offset;
+    unsigned int descriptor_count;
+    uint32_t binding;
+
+    uint32_t descriptor_magic;
+    unsigned int register_space;
+    unsigned int base_register_idx;
+};
+
+struct d3d12_root_descriptor_table
+{
+    unsigned int range_count;
+    struct d3d12_root_descriptor_table_range *ranges;
+};
+
+struct d3d12_root_constant
+{
+    VkShaderStageFlags stage_flags;
+    uint32_t offset;
+};
+
+struct d3d12_root_descriptor
+{
+    uint32_t binding;
+};
+
+struct d3d12_root_parameter
+{
+    D3D12_ROOT_PARAMETER_TYPE parameter_type;
+    union
+    {
+        struct d3d12_root_constant constant;
+        struct d3d12_root_descriptor descriptor;
+        struct d3d12_root_descriptor_table descriptor_table;
+    } u;
+};
+
+/* ID3D12RootSignature */
+struct d3d12_root_signature
+{
+    ID3D12RootSignature ID3D12RootSignature_iface;
+    LONG refcount;
+
+    VkPipelineLayout vk_pipeline_layout;
+    VkDescriptorSetLayout vk_push_set_layout;
+    VkDescriptorSetLayout vk_set_layout;
+
+    struct d3d12_root_parameter *parameters;
+    unsigned int parameter_count;
+    uint32_t main_set;
+
+    uint64_t descriptor_table_mask;
+    uint32_t push_descriptor_mask;
+
+    D3D12_ROOT_SIGNATURE_FLAGS flags;
+
+    unsigned int descriptor_count;
+    struct vkd3d_shader_resource_binding *descriptor_mapping;
+
+    unsigned int root_constant_count;
+    struct vkd3d_shader_push_constant_buffer *root_constants;
+
+    unsigned int root_descriptor_count;
+
+    unsigned int push_constant_range_count;
+    /* Only a single push constant range may include the same stage in Vulkan. */
+    VkPushConstantRange push_constant_ranges[D3D12_SHADER_VISIBILITY_PIXEL + 1];
+
+    unsigned int static_sampler_count;
+    VkSampler *static_samplers;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_root_signature_create(struct d3d12_device *device, const void *bytecode,
+        size_t bytecode_length, struct d3d12_root_signature **root_signature) DECLSPEC_HIDDEN;
+struct d3d12_root_signature *unsafe_impl_from_ID3D12RootSignature(ID3D12RootSignature *iface) DECLSPEC_HIDDEN;
+
+int vkd3d_parse_root_signature_v_1_0(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_versioned_root_signature_desc *desc) DECLSPEC_HIDDEN;
+
+struct d3d12_graphics_pipeline_state
+{
+    VkPipelineShaderStageCreateInfo stages[VKD3D_MAX_SHADER_STAGES];
+    size_t stage_count;
+
+    VkVertexInputAttributeDescription attributes[D3D12_VS_INPUT_REGISTER_COUNT];
+    VkVertexInputRate input_rates[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    VkVertexInputBindingDivisorDescriptionEXT instance_divisors[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    size_t instance_divisor_count;
+    size_t attribute_count;
+
+    VkPipelineColorBlendAttachmentState blend_attachments[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    unsigned int rt_count;
+    unsigned int null_attachment_mask;
+    VkFormat dsv_format;
+    VkFormat rtv_formats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    VkRenderPass render_pass;
+
+    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE index_buffer_strip_cut_value;
+    VkPipelineRasterizationStateCreateInfo rs_desc;
+    VkPipelineMultisampleStateCreateInfo ms_desc;
+    VkPipelineDepthStencilStateCreateInfo ds_desc;
+
+    VkSampleMask sample_mask[2];
+    VkPipelineRasterizationDepthClipStateCreateInfoEXT rs_depth_clip_info;
+    VkPipelineRasterizationStateStreamCreateInfoEXT rs_stream_info;
+
+    const struct d3d12_root_signature *root_signature;
+
+    struct list compiled_pipelines;
+
+    bool xfb_enabled;
+};
+
+static inline unsigned int dsv_attachment_mask(const struct d3d12_graphics_pipeline_state *graphics)
+{
+    return 1u << graphics->rt_count;
+}
+
+struct d3d12_compute_pipeline_state
+{
+    VkPipeline vk_pipeline;
+};
+
+/* ID3D12PipelineState */
+struct d3d12_pipeline_state
+{
+    ID3D12PipelineState ID3D12PipelineState_iface;
+    LONG refcount;
+
+    union
+    {
+        struct d3d12_graphics_pipeline_state graphics;
+        struct d3d12_compute_pipeline_state compute;
+    } u;
+    VkPipelineBindPoint vk_bind_point;
+
+    VkPipelineLayout vk_pipeline_layout;
+    VkDescriptorSetLayout vk_set_layout;
+    uint32_t set_index;
+
+    struct vkd3d_shader_uav_counter_binding *uav_counters;
+    unsigned int uav_counter_count;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+static inline bool d3d12_pipeline_state_is_compute(const struct d3d12_pipeline_state *state)
+{
+    return state && state->vk_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE;
+}
+
+static inline bool d3d12_pipeline_state_is_graphics(const struct d3d12_pipeline_state *state)
+{
+    return state && state->vk_bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS;
+}
+
+static inline bool d3d12_pipeline_state_has_unknown_dsv_format(struct d3d12_pipeline_state *state)
+{
+    if (d3d12_pipeline_state_is_graphics(state))
+    {
+        struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
+
+        return graphics->null_attachment_mask & dsv_attachment_mask(graphics);
+    }
+
+    return false;
+}
+
+HRESULT d3d12_pipeline_state_create_compute(struct d3d12_device *device,
+        const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state) DECLSPEC_HIDDEN;
+HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device,
+        const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state) DECLSPEC_HIDDEN;
+VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
+        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides, VkFormat dsv_format,
+        VkRenderPass *vk_render_pass) DECLSPEC_HIDDEN;
+struct d3d12_pipeline_state *unsafe_impl_from_ID3D12PipelineState(ID3D12PipelineState *iface) DECLSPEC_HIDDEN;
+
+struct vkd3d_buffer
+{
+    VkBuffer vk_buffer;
+    VkDeviceMemory vk_memory;
+};
+
+/* ID3D12CommandAllocator */
+struct d3d12_command_allocator
+{
+    ID3D12CommandAllocator ID3D12CommandAllocator_iface;
+    LONG refcount;
+
+    D3D12_COMMAND_LIST_TYPE type;
+    VkQueueFlags vk_queue_flags;
+
+    VkCommandPool vk_command_pool;
+
+    VkDescriptorPool vk_descriptor_pool;
+
+    VkDescriptorPool *free_descriptor_pools;
+    size_t free_descriptor_pools_size;
+    size_t free_descriptor_pool_count;
+
+    VkRenderPass *passes;
+    size_t passes_size;
+    size_t pass_count;
+
+    VkFramebuffer *framebuffers;
+    size_t framebuffers_size;
+    size_t framebuffer_count;
+
+    VkDescriptorPool *descriptor_pools;
+    size_t descriptor_pools_size;
+    size_t descriptor_pool_count;
+
+    struct vkd3d_view **views;
+    size_t views_size;
+    size_t view_count;
+
+    VkBufferView *buffer_views;
+    size_t buffer_views_size;
+    size_t buffer_view_count;
+
+    struct vkd3d_buffer *transfer_buffers;
+    size_t transfer_buffers_size;
+    size_t transfer_buffer_count;
+
+    VkCommandBuffer *command_buffers;
+    size_t command_buffers_size;
+    size_t command_buffer_count;
+
+    struct d3d12_command_list *current_command_list;
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_command_allocator_create(struct d3d12_device *device,
+        D3D12_COMMAND_LIST_TYPE type, struct d3d12_command_allocator **allocator) DECLSPEC_HIDDEN;
+
+struct vkd3d_push_descriptor
+{
+    union
+    {
+        VkBufferView vk_buffer_view;
+        struct
+        {
+            VkBuffer vk_buffer;
+            VkDeviceSize offset;
+        } cbv;
+    } u;
+};
+
+struct vkd3d_pipeline_bindings
+{
+    const struct d3d12_root_signature *root_signature;
+
+    VkPipelineBindPoint vk_bind_point;
+    VkDescriptorSet descriptor_set;
+    bool in_use;
+
+    D3D12_GPU_DESCRIPTOR_HANDLE descriptor_tables[D3D12_MAX_ROOT_COST];
+    uint64_t descriptor_table_dirty_mask;
+    uint64_t descriptor_table_active_mask;
+
+    VkBufferView *vk_uav_counter_views;
+    size_t vk_uav_counter_views_size;
+    bool uav_counters_dirty;
+
+    /* Needed when VK_KHR_push_descriptor is not available. */
+    struct vkd3d_push_descriptor push_descriptors[D3D12_MAX_ROOT_COST / 2];
+    uint32_t push_descriptor_dirty_mask;
+    uint32_t push_descriptor_active_mask;
+};
+
+enum vkd3d_pipeline_bind_point
+{
+    VKD3D_PIPELINE_BIND_POINT_GRAPHICS = 0x0,
+    VKD3D_PIPELINE_BIND_POINT_COMPUTE = 0x1,
+    VKD3D_PIPELINE_BIND_POINT_COUNT = 0x2,
+};
+
+/* ID3D12CommandList */
+struct d3d12_command_list
+{
+    ID3D12GraphicsCommandList2 ID3D12GraphicsCommandList2_iface;
+    LONG refcount;
+
+    D3D12_COMMAND_LIST_TYPE type;
+    VkQueueFlags vk_queue_flags;
+
+    bool is_recording;
+    bool is_valid;
+    VkCommandBuffer vk_command_buffer;
+
+    uint32_t strides[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    D3D12_PRIMITIVE_TOPOLOGY primitive_topology;
+
+    DXGI_FORMAT index_buffer_format;
+
+    VkImageView rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    VkImageView dsv;
+    unsigned int fb_width;
+    unsigned int fb_height;
+    unsigned int fb_layer_count;
+    VkFormat dsv_format;
+
+    bool xfb_enabled;
+
+    bool is_predicated;
+
+    VkFramebuffer current_framebuffer;
+    VkPipeline current_pipeline;
+    VkRenderPass pso_render_pass;
+    VkRenderPass current_render_pass;
+    struct vkd3d_pipeline_bindings pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COUNT];
+
+    struct d3d12_pipeline_state *state;
+
+    struct d3d12_command_allocator *allocator;
+    struct d3d12_device *device;
+
+    VkBuffer so_counter_buffers[D3D12_SO_BUFFER_SLOT_COUNT];
+    VkDeviceSize so_counter_buffer_offsets[D3D12_SO_BUFFER_SLOT_COUNT];
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_command_list_create(struct d3d12_device *device,
+        UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *allocator_iface,
+        ID3D12PipelineState *initial_pipeline_state, struct d3d12_command_list **list) DECLSPEC_HIDDEN;
+
+struct vkd3d_queue
+{
+    /* Access to VkQueue must be externally synchronized. */
+    pthread_mutex_t mutex;
+
+    VkQueue vk_queue;
+
+    uint64_t completed_sequence_number;
+    uint64_t submitted_sequence_number;
+
+    uint32_t vk_family_index;
+    VkQueueFlags vk_queue_flags;
+    uint32_t timestamp_bits;
+
+    struct
+    {
+        VkSemaphore vk_semaphore;
+        uint64_t sequence_number;
+    } *semaphores;
+    size_t semaphores_size;
+    size_t semaphore_count;
+
+    VkSemaphore old_vk_semaphores[VKD3D_MAX_VK_SYNC_OBJECTS];
+};
+
+VkQueue vkd3d_queue_acquire(struct vkd3d_queue *queue) DECLSPEC_HIDDEN;
+HRESULT vkd3d_queue_create(struct d3d12_device *device,
+        uint32_t family_index, const VkQueueFamilyProperties *properties,
+        struct vkd3d_queue **queue) DECLSPEC_HIDDEN;
+void vkd3d_queue_destroy(struct vkd3d_queue *queue, struct d3d12_device *device) DECLSPEC_HIDDEN;
+void vkd3d_queue_release(struct vkd3d_queue *queue) DECLSPEC_HIDDEN;
+
+/* ID3D12CommandQueue */
+struct d3d12_command_queue
+{
+    ID3D12CommandQueue ID3D12CommandQueue_iface;
+    LONG refcount;
+
+    D3D12_COMMAND_QUEUE_DESC desc;
+
+    struct vkd3d_queue *vkd3d_queue;
+
+    const struct d3d12_fence *last_waited_fence;
+    uint64_t last_waited_fence_value;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_command_queue_create(struct d3d12_device *device,
+        const D3D12_COMMAND_QUEUE_DESC *desc, struct d3d12_command_queue **queue) DECLSPEC_HIDDEN;
+
+/* ID3D12CommandSignature */
+struct d3d12_command_signature
+{
+    ID3D12CommandSignature ID3D12CommandSignature_iface;
+    LONG refcount;
+
+    D3D12_COMMAND_SIGNATURE_DESC desc;
+
+    struct d3d12_device *device;
+
+    struct vkd3d_private_store private_store;
+};
+
+HRESULT d3d12_command_signature_create(struct d3d12_device *device, const D3D12_COMMAND_SIGNATURE_DESC *desc,
+        struct d3d12_command_signature **signature) DECLSPEC_HIDDEN;
+struct d3d12_command_signature *unsafe_impl_from_ID3D12CommandSignature(ID3D12CommandSignature *iface) DECLSPEC_HIDDEN;
+
+/* NULL resources */
+struct vkd3d_null_resources
+{
+    VkBuffer vk_buffer;
+    VkDeviceMemory vk_buffer_memory;
+
+    VkBuffer vk_storage_buffer;
+    VkDeviceMemory vk_storage_buffer_memory;
+
+    VkImage vk_2d_image;
+    VkDeviceMemory vk_2d_image_memory;
+
+    VkImage vk_2d_storage_image;
+    VkDeviceMemory vk_2d_storage_image_memory;
+};
+
+HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+void vkd3d_destroy_null_resources(struct vkd3d_null_resources *null_resources,
+        struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+struct vkd3d_format_compatibility_list
+{
+    DXGI_FORMAT typeless_format;
+    unsigned int format_count;
+    VkFormat vk_formats[VKD3D_MAX_COMPATIBLE_FORMAT_COUNT];
+};
+
+struct vkd3d_uav_clear_args
+{
+    VkClearColorValue colour;
+    VkOffset2D offset;
+    VkExtent2D extent;
+};
+
+struct vkd3d_uav_clear_pipelines
+{
+    VkPipeline buffer;
+    VkPipeline image_1d;
+    VkPipeline image_1d_array;
+    VkPipeline image_2d;
+    VkPipeline image_2d_array;
+    VkPipeline image_3d;
+};
+
+struct vkd3d_uav_clear_state
+{
+    VkDescriptorSetLayout vk_set_layout_buffer;
+    VkDescriptorSetLayout vk_set_layout_image;
+
+    VkPipelineLayout vk_pipeline_layout_buffer;
+    VkPipelineLayout vk_pipeline_layout_image;
+
+    struct vkd3d_uav_clear_pipelines pipelines_float;
+    struct vkd3d_uav_clear_pipelines pipelines_uint;
+};
+
+HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d3d12_device *device) DECLSPEC_HIDDEN;
+void vkd3d_uav_clear_state_cleanup(struct vkd3d_uav_clear_state *state, struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+/* ID3D12Device */
+struct d3d12_device
+{
+    ID3D12Device ID3D12Device_iface;
+    LONG refcount;
+
+    VkDevice vk_device;
+    VkPhysicalDevice vk_physical_device;
+    struct vkd3d_vk_device_procs vk_procs;
+    PFN_vkd3d_signal_event signal_event;
+    size_t wchar_size;
+
+    struct vkd3d_gpu_va_allocator gpu_va_allocator;
+    struct vkd3d_fence_worker fence_worker;
+
+    pthread_mutex_t mutex;
+    pthread_mutex_t desc_mutex[8];
+    struct vkd3d_render_pass_cache render_pass_cache;
+    VkPipelineCache vk_pipeline_cache;
+
+    VkPhysicalDeviceMemoryProperties memory_properties;
+
+    D3D12_FEATURE_DATA_D3D12_OPTIONS feature_options;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS1 feature_options1;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS2 feature_options2;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS3 feature_options3;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS4 feature_options4;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS5 feature_options5;
+
+    struct vkd3d_vulkan_info vk_info;
+
+    struct vkd3d_queue *direct_queue;
+    struct vkd3d_queue *compute_queue;
+    struct vkd3d_queue *copy_queue;
+    uint32_t queue_family_indices[VKD3D_MAX_QUEUE_FAMILY_COUNT];
+    unsigned int queue_family_count;
+
+    struct vkd3d_instance *vkd3d_instance;
+
+    IUnknown *parent;
+    LUID adapter_luid;
+
+    struct vkd3d_private_store private_store;
+
+    HRESULT removed_reason;
+
+    const struct vkd3d_format *depth_stencil_formats;
+    unsigned int format_compatibility_list_count;
+    const struct vkd3d_format_compatibility_list *format_compatibility_lists;
+    struct vkd3d_null_resources null_resources;
+    struct vkd3d_uav_clear_state uav_clear_state;
+};
+
+HRESULT d3d12_device_create(struct vkd3d_instance *instance,
+        const struct vkd3d_device_create_info *create_info, struct d3d12_device **device) DECLSPEC_HIDDEN;
+struct vkd3d_queue *d3d12_device_get_vkd3d_queue(struct d3d12_device *device,
+        D3D12_COMMAND_LIST_TYPE type) DECLSPEC_HIDDEN;
+bool d3d12_device_is_uma(struct d3d12_device *device, bool *coherent) DECLSPEC_HIDDEN;
+void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
+        const char *message, ...) VKD3D_PRINTF_FUNC(3, 4) DECLSPEC_HIDDEN;
+struct d3d12_device *unsafe_impl_from_ID3D12Device(ID3D12Device *iface) DECLSPEC_HIDDEN;
+
+static inline HRESULT d3d12_device_query_interface(struct d3d12_device *device, REFIID iid, void **object)
+{
+    return ID3D12Device_QueryInterface(&device->ID3D12Device_iface, iid, object);
+}
+
+static inline ULONG d3d12_device_add_ref(struct d3d12_device *device)
+{
+    return ID3D12Device_AddRef(&device->ID3D12Device_iface);
+}
+
+static inline ULONG d3d12_device_release(struct d3d12_device *device)
+{
+    return ID3D12Device_Release(&device->ID3D12Device_iface);
+}
+
+static inline unsigned int d3d12_device_get_descriptor_handle_increment_size(struct d3d12_device *device,
+        D3D12_DESCRIPTOR_HEAP_TYPE descriptor_type)
+{
+    return ID3D12Device_GetDescriptorHandleIncrementSize(&device->ID3D12Device_iface, descriptor_type);
+}
+
+static inline pthread_mutex_t *d3d12_device_get_descriptor_mutex(struct d3d12_device *device,
+        const struct d3d12_desc *descriptor)
+{
+    STATIC_ASSERT(!(ARRAY_SIZE(device->desc_mutex) & (ARRAY_SIZE(device->desc_mutex) - 1)));
+    uintptr_t idx = (uintptr_t)descriptor;
+
+    idx ^= idx >> 12;
+    idx ^= idx >> 6;
+    idx ^= idx >> 3;
+
+    return &device->desc_mutex[idx & (ARRAY_SIZE(device->desc_mutex) - 1)];
+}
+
+/* utils */
+enum vkd3d_format_type
+{
+    VKD3D_FORMAT_TYPE_OTHER,
+    VKD3D_FORMAT_TYPE_TYPELESS,
+    VKD3D_FORMAT_TYPE_SINT,
+    VKD3D_FORMAT_TYPE_UINT,
+};
+
+struct vkd3d_format
+{
+    DXGI_FORMAT dxgi_format;
+    VkFormat vk_format;
+    size_t byte_count;
+    size_t block_width;
+    size_t block_height;
+    size_t block_byte_count;
+    VkImageAspectFlags vk_aspect_mask;
+    unsigned int plane_count;
+    enum vkd3d_format_type type;
+    bool is_emulated;
+};
+
+static inline size_t vkd3d_format_get_data_offset(const struct vkd3d_format *format,
+        unsigned int row_pitch, unsigned int slice_pitch,
+        unsigned int x, unsigned int y, unsigned int z)
+{
+    return z * slice_pitch
+            + (y / format->block_height) * row_pitch
+            + (x / format->block_width) * format->byte_count * format->block_byte_count;
+}
+
+static inline bool vkd3d_format_is_compressed(const struct vkd3d_format *format)
+{
+    return format->block_byte_count != 1;
+}
+
+void vkd3d_format_copy_data(const struct vkd3d_format *format, const uint8_t *src,
+        unsigned int src_row_pitch, unsigned int src_slice_pitch, uint8_t *dst, unsigned int dst_row_pitch,
+        unsigned int dst_slice_pitch, unsigned int w, unsigned int h, unsigned int d) DECLSPEC_HIDDEN;
+
+const struct vkd3d_format *vkd3d_get_format(const struct d3d12_device *device,
+        DXGI_FORMAT dxgi_format, bool depth_stencil) DECLSPEC_HIDDEN;
+const struct vkd3d_format *vkd3d_find_uint_format(const struct d3d12_device *device,
+        DXGI_FORMAT dxgi_format) DECLSPEC_HIDDEN;
+
+HRESULT vkd3d_init_format_info(struct d3d12_device *device) DECLSPEC_HIDDEN;
+void vkd3d_cleanup_format_info(struct d3d12_device *device) DECLSPEC_HIDDEN;
+
+static inline const struct vkd3d_format *vkd3d_format_from_d3d12_resource_desc(
+        const struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc, DXGI_FORMAT view_format)
+{
+    return vkd3d_get_format(device, view_format ? view_format : desc->Format,
+            desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
+}
+
+static inline bool d3d12_box_is_empty(const D3D12_BOX *box)
+{
+    return box->right <= box->left || box->bottom <= box->top || box->back <= box->front;
+}
+
+static inline unsigned int d3d12_resource_desc_get_width(const D3D12_RESOURCE_DESC *desc,
+        unsigned int miplevel_idx)
+{
+    return max(1, desc->Width >> miplevel_idx);
+}
+
+static inline unsigned int d3d12_resource_desc_get_height(const D3D12_RESOURCE_DESC *desc,
+        unsigned int miplevel_idx)
+{
+    return max(1, desc->Height >> miplevel_idx);
+}
+
+static inline unsigned int d3d12_resource_desc_get_depth(const D3D12_RESOURCE_DESC *desc,
+        unsigned int miplevel_idx)
+{
+    unsigned int d = desc->Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc->DepthOrArraySize;
+    return max(1, d >> miplevel_idx);
+}
+
+static inline unsigned int d3d12_resource_desc_get_layer_count(const D3D12_RESOURCE_DESC *desc)
+{
+    return desc->Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? desc->DepthOrArraySize : 1;
+}
+
+static inline unsigned int d3d12_resource_desc_get_sub_resource_count(const D3D12_RESOURCE_DESC *desc)
+{
+    return d3d12_resource_desc_get_layer_count(desc) * desc->MipLevels;
+}
+
+static inline unsigned int vkd3d_compute_workgroup_count(unsigned int thread_count, unsigned int workgroup_size)
+{
+    return (thread_count + workgroup_size - 1) / workgroup_size;
+}
+
+VkCompareOp vk_compare_op_from_d3d12(D3D12_COMPARISON_FUNC op) DECLSPEC_HIDDEN;
+VkSampleCountFlagBits vk_samples_from_dxgi_sample_desc(const DXGI_SAMPLE_DESC *desc) DECLSPEC_HIDDEN;
+VkSampleCountFlagBits vk_samples_from_sample_count(unsigned int sample_count) DECLSPEC_HIDDEN;
+
+bool is_valid_feature_level(D3D_FEATURE_LEVEL feature_level) DECLSPEC_HIDDEN;
+
+bool is_valid_resource_state(D3D12_RESOURCE_STATES state) DECLSPEC_HIDDEN;
+bool is_write_resource_state(D3D12_RESOURCE_STATES state) DECLSPEC_HIDDEN;
+
+HRESULT return_interface(void *iface, REFIID iface_iid,
+        REFIID requested_iid, void **object) DECLSPEC_HIDDEN;
+
+const char *debug_d3d12_box(const D3D12_BOX *box) DECLSPEC_HIDDEN;
+const char *debug_d3d12_shader_component_mapping(unsigned int mapping) DECLSPEC_HIDDEN;
+const char *debug_vk_extent_3d(VkExtent3D extent) DECLSPEC_HIDDEN;
+const char *debug_vk_memory_heap_flags(VkMemoryHeapFlags flags) DECLSPEC_HIDDEN;
+const char *debug_vk_memory_property_flags(VkMemoryPropertyFlags flags) DECLSPEC_HIDDEN;
+const char *debug_vk_queue_flags(VkQueueFlags flags) DECLSPEC_HIDDEN;
+
+static inline void debug_ignored_node_mask(unsigned int mask)
+{
+    if (mask && mask != 1)
+        FIXME("Ignoring node mask 0x%08x.\n", mask);
+}
+
+HRESULT vkd3d_load_vk_global_procs(struct vkd3d_vk_global_procs *procs,
+        PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) DECLSPEC_HIDDEN;
+HRESULT vkd3d_load_vk_instance_procs(struct vkd3d_vk_instance_procs *procs,
+        const struct vkd3d_vk_global_procs *global_procs, VkInstance instance) DECLSPEC_HIDDEN;
+HRESULT vkd3d_load_vk_device_procs(struct vkd3d_vk_device_procs *procs,
+        const struct vkd3d_vk_instance_procs *parent_procs, VkDevice device) DECLSPEC_HIDDEN;
+
+extern const char vkd3d_build[];
+
+bool vkd3d_get_program_name(char program_name[PATH_MAX]) DECLSPEC_HIDDEN;
+
+static inline void vkd3d_set_thread_name(const char *name)
+{
+#if defined(HAVE_PTHREAD_SETNAME_NP_2)
+    pthread_setname_np(pthread_self(), name);
+#elif defined(HAVE_PTHREAD_SETNAME_NP_1)
+    pthread_setname_np(name);
+#endif
+}
+
+VkResult vkd3d_set_vk_object_name_utf8(struct d3d12_device *device, uint64_t vk_object,
+        VkDebugReportObjectTypeEXT vk_object_type, const char *name) DECLSPEC_HIDDEN;
+HRESULT vkd3d_set_vk_object_name(struct d3d12_device *device, uint64_t vk_object,
+        VkDebugReportObjectTypeEXT vk_object_type, const WCHAR *name) DECLSPEC_HIDDEN;
+
+static inline void vk_prepend_struct(void *header, void *structure)
+{
+    VkBaseOutStructure *vk_header = header, *vk_structure = structure;
+
+    assert(!vk_structure->pNext);
+    vk_structure->pNext = vk_header->pNext;
+    vk_header->pNext = vk_structure;
+}
+
+#endif  /* __VKD3D_PRIVATE_H */
diff --git a/dlls/vkd3d/libs/vkd3d/vkd3d_shaders.h b/dlls/vkd3d/libs/vkd3d/vkd3d_shaders.h
new file mode 100644
index 00000000000..b2a90cdbf3c
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/vkd3d_shaders.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2019 Philip Rebohle
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_SHADERS_H
+#define __VKD3D_SHADERS_H
+
+static const uint32_t cs_uav_clear_buffer_float_code[] =
+{
+#if 0
+    RWBuffer<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(128, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0xe114ba61, 0xff6a0d0b, 0x7b25c8f4, 0xfcf7cf22, 0x00000001, 0x0000010c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400089c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000080, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000,
+    0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_buffer_uint_code[] =
+{
+#if 0
+    RWBuffer<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(128, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x3afd0cfd, 0x5145c166, 0x5b9f76b8, 0xa73775cd, 0x00000001, 0x0000010c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400089c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000080, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000,
+    0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_1d_array_float_code[] =
+{
+#if 0
+    RWTexture1DArray<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(64, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x3d73bc2d, 0x2b635f3d, 0x6bf98e92, 0xbe0aa5d9, 0x00000001, 0x0000011c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000c8, 0x00050050, 0x00000032, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400389c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x04000036, 0x001000e2, 0x00000000, 0x00020556, 0x080000a4, 0x0011e0f2, 0x00000000,
+    0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_1d_array_uint_code[] =
+{
+#if 0
+    RWTexture1DArray<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(64, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x2f0ca457, 0x72068b34, 0xd9dadc2b, 0xd3178c3e, 0x00000001, 0x0000011c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000c8, 0x00050050, 0x00000032, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400389c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x04000036, 0x001000e2, 0x00000000, 0x00020556, 0x080000a4, 0x0011e0f2, 0x00000000,
+    0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_1d_float_code[] =
+{
+#if 0
+    RWTexture1D<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(64, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x05266503, 0x4b97006f, 0x01a5cc63, 0xe617d0a1, 0x00000001, 0x0000010c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400109c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000,
+    0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_1d_uint_code[] =
+{
+#if 0
+    RWTexture1D<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(64, 1, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (thread_id.x < u_info.dst_extent.x)
+            dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x19d5c8f2, 0x3ca4ac24, 0x9e258499, 0xf0463fd6, 0x00000001, 0x0000010c, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400109c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001,
+    0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f,
+    0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000,
+    0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000,
+    0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_2d_array_float_code[] =
+{
+#if 0
+    RWTexture2DArray<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x924d2d2c, 0xb9166376, 0x99f83871, 0x8ef65025, 0x00000001, 0x00000138, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400409c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001,
+    0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46,
+    0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_2d_array_uint_code[] =
+{
+#if 0
+    RWTexture2DArray<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0xa92219d4, 0xa2c5e47d, 0x0d308500, 0xf32197b4, 0x00000001, 0x00000138, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400409c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001,
+    0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46,
+    0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_2d_float_code[] =
+{
+#if 0
+    RWTexture2D<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x6e735b3f, 0x7348c4fa, 0xb3634e42, 0x50e2d99b, 0x00000001, 0x00000128, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000d4, 0x00050050, 0x00000035, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400189c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x001000f2, 0x00000000, 0x00020546, 0x00208546, 0x00000000, 0x00000001,
+    0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000,
+    0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_2d_uint_code[] =
+{
+#if 0
+    RWTexture2D<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0xf01db5dd, 0xc7dc5e55, 0xb017c1a8, 0x55abd52d, 0x00000001, 0x00000128, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000d4, 0x00050050, 0x00000035, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400189c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x001000f2, 0x00000000, 0x00020546, 0x00208546, 0x00000000, 0x00000001,
+    0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000,
+    0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_3d_float_code[] =
+{
+#if 0
+    RWTexture3D<float4> dst;
+
+    struct
+    {
+        float4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x5d8f36a0, 0x30fa86a5, 0xfec7f2ef, 0xdfd76cbb, 0x00000001, 0x00000138, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400289c, 0x0011e000, 0x00000000, 0x00005555,
+    0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001,
+    0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46,
+    0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+static const uint32_t cs_uav_clear_3d_uint_code[] =
+{
+#if 0
+    RWTexture3D<uint4> dst;
+
+    struct
+    {
+        uint4 clear_value;
+        int2 dst_offset;
+        int2 dst_extent;
+    } u_info;
+
+    [numthreads(8, 8, 1)]
+    void main(int3 thread_id : SV_DispatchThreadID)
+    {
+        if (all(thread_id.xy < u_info.dst_extent.xy))
+            dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value;
+    }
+#endif
+    0x43425844, 0x5b9c95b1, 0xc9bde4e3, 0x9aaff806, 0x24a1d264, 0x00000001, 0x00000138, 0x00000003,
+    0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+    0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a,
+    0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400289c, 0x0011e000, 0x00000000, 0x00004444,
+    0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001,
+    0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001,
+    0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+    0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001,
+    0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46,
+    0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e,
+};
+
+#endif /* __VKD3D_SHADERS_H */
diff --git a/dlls/vkd3d/libs/vkd3d/vulkan_procs.h b/dlls/vkd3d/libs/vkd3d/vulkan_procs.h
new file mode 100644
index 00000000000..ec29eb45302
--- /dev/null
+++ b/dlls/vkd3d/libs/vkd3d/vulkan_procs.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef VK_INSTANCE_PFN
+# define VK_INSTANCE_PFN(x)
+#endif
+
+#ifndef VK_INSTANCE_EXT_PFN
+# define VK_INSTANCE_EXT_PFN(x)
+#endif
+
+#ifndef VK_DEVICE_PFN
+# define VK_DEVICE_PFN(x)
+#endif
+
+#ifndef VK_DEVICE_EXT_PFN
+# define VK_DEVICE_EXT_PFN(x)
+#endif
+
+/* Instance functions (obtained by vkGetInstanceProcAddr). */
+VK_INSTANCE_PFN(vkDestroyInstance) /* Load vkDestroyInstance() first. */
+VK_INSTANCE_PFN(vkCreateDevice)
+VK_INSTANCE_PFN(vkEnumerateDeviceExtensionProperties)
+VK_INSTANCE_PFN(vkEnumerateDeviceLayerProperties)
+VK_INSTANCE_PFN(vkEnumeratePhysicalDevices)
+VK_INSTANCE_PFN(vkGetDeviceProcAddr)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceFormatProperties)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceImageFormatProperties)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceProperties)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceQueueFamilyProperties)
+VK_INSTANCE_PFN(vkGetPhysicalDeviceSparseImageFormatProperties)
+
+/* VK_KHR_get_physical_device_properties2 */
+VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceFeatures2KHR)
+VK_INSTANCE_EXT_PFN(vkGetPhysicalDeviceProperties2KHR)
+
+/* VK_EXT_debug_report */
+VK_INSTANCE_EXT_PFN(vkCreateDebugReportCallbackEXT)
+VK_INSTANCE_EXT_PFN(vkDestroyDebugReportCallbackEXT)
+
+/* Device functions (obtained by vkGetDeviceProcAddr). */
+VK_DEVICE_PFN(vkDestroyDevice) /* Load vkDestroyDevice() first. */
+VK_DEVICE_PFN(vkAllocateCommandBuffers)
+VK_DEVICE_PFN(vkAllocateDescriptorSets)
+VK_DEVICE_PFN(vkAllocateMemory)
+VK_DEVICE_PFN(vkBeginCommandBuffer)
+VK_DEVICE_PFN(vkBindBufferMemory)
+VK_DEVICE_PFN(vkBindImageMemory)
+VK_DEVICE_PFN(vkCmdBeginQuery)
+VK_DEVICE_PFN(vkCmdBeginRenderPass)
+VK_DEVICE_PFN(vkCmdBindDescriptorSets)
+VK_DEVICE_PFN(vkCmdBindIndexBuffer)
+VK_DEVICE_PFN(vkCmdBindPipeline)
+VK_DEVICE_PFN(vkCmdBindVertexBuffers)
+VK_DEVICE_PFN(vkCmdBlitImage)
+VK_DEVICE_PFN(vkCmdClearAttachments)
+VK_DEVICE_PFN(vkCmdClearColorImage)
+VK_DEVICE_PFN(vkCmdClearDepthStencilImage)
+VK_DEVICE_PFN(vkCmdCopyBuffer)
+VK_DEVICE_PFN(vkCmdCopyBufferToImage)
+VK_DEVICE_PFN(vkCmdCopyImage)
+VK_DEVICE_PFN(vkCmdCopyImageToBuffer)
+VK_DEVICE_PFN(vkCmdCopyQueryPoolResults)
+VK_DEVICE_PFN(vkCmdDispatch)
+VK_DEVICE_PFN(vkCmdDispatchIndirect)
+VK_DEVICE_PFN(vkCmdDraw)
+VK_DEVICE_PFN(vkCmdDrawIndexed)
+VK_DEVICE_PFN(vkCmdDrawIndexedIndirect)
+VK_DEVICE_PFN(vkCmdDrawIndirect)
+VK_DEVICE_PFN(vkCmdEndQuery)
+VK_DEVICE_PFN(vkCmdEndRenderPass)
+VK_DEVICE_PFN(vkCmdExecuteCommands)
+VK_DEVICE_PFN(vkCmdFillBuffer)
+VK_DEVICE_PFN(vkCmdNextSubpass)
+VK_DEVICE_PFN(vkCmdPipelineBarrier)
+VK_DEVICE_PFN(vkCmdPushConstants)
+VK_DEVICE_PFN(vkCmdResetEvent)
+VK_DEVICE_PFN(vkCmdResetQueryPool)
+VK_DEVICE_PFN(vkCmdResolveImage)
+VK_DEVICE_PFN(vkCmdSetBlendConstants)
+VK_DEVICE_PFN(vkCmdSetDepthBias)
+VK_DEVICE_PFN(vkCmdSetDepthBounds)
+VK_DEVICE_PFN(vkCmdSetEvent)
+VK_DEVICE_PFN(vkCmdSetLineWidth)
+VK_DEVICE_PFN(vkCmdSetScissor)
+VK_DEVICE_PFN(vkCmdSetStencilCompareMask)
+VK_DEVICE_PFN(vkCmdSetStencilReference)
+VK_DEVICE_PFN(vkCmdSetStencilWriteMask)
+VK_DEVICE_PFN(vkCmdSetViewport)
+VK_DEVICE_PFN(vkCmdUpdateBuffer)
+VK_DEVICE_PFN(vkCmdWaitEvents)
+VK_DEVICE_PFN(vkCmdWriteTimestamp)
+VK_DEVICE_PFN(vkCreateBuffer)
+VK_DEVICE_PFN(vkCreateBufferView)
+VK_DEVICE_PFN(vkCreateCommandPool)
+VK_DEVICE_PFN(vkCreateComputePipelines)
+VK_DEVICE_PFN(vkCreateDescriptorPool)
+VK_DEVICE_PFN(vkCreateDescriptorSetLayout)
+VK_DEVICE_PFN(vkCreateEvent)
+VK_DEVICE_PFN(vkCreateFence)
+VK_DEVICE_PFN(vkCreateFramebuffer)
+VK_DEVICE_PFN(vkCreateGraphicsPipelines)
+VK_DEVICE_PFN(vkCreateImage)
+VK_DEVICE_PFN(vkCreateImageView)
+VK_DEVICE_PFN(vkCreatePipelineCache)
+VK_DEVICE_PFN(vkCreatePipelineLayout)
+VK_DEVICE_PFN(vkCreateQueryPool)
+VK_DEVICE_PFN(vkCreateRenderPass)
+VK_DEVICE_PFN(vkCreateSampler)
+VK_DEVICE_PFN(vkCreateSemaphore)
+VK_DEVICE_PFN(vkCreateShaderModule)
+VK_DEVICE_PFN(vkDestroyBuffer)
+VK_DEVICE_PFN(vkDestroyBufferView)
+VK_DEVICE_PFN(vkDestroyCommandPool)
+VK_DEVICE_PFN(vkDestroyDescriptorPool)
+VK_DEVICE_PFN(vkDestroyDescriptorSetLayout)
+VK_DEVICE_PFN(vkDestroyEvent)
+VK_DEVICE_PFN(vkDestroyFence)
+VK_DEVICE_PFN(vkDestroyFramebuffer)
+VK_DEVICE_PFN(vkDestroyImage)
+VK_DEVICE_PFN(vkDestroyImageView)
+VK_DEVICE_PFN(vkDestroyPipeline)
+VK_DEVICE_PFN(vkDestroyPipelineCache)
+VK_DEVICE_PFN(vkDestroyPipelineLayout)
+VK_DEVICE_PFN(vkDestroyQueryPool)
+VK_DEVICE_PFN(vkDestroyRenderPass)
+VK_DEVICE_PFN(vkDestroySampler)
+VK_DEVICE_PFN(vkDestroySemaphore)
+VK_DEVICE_PFN(vkDestroyShaderModule)
+VK_DEVICE_PFN(vkDeviceWaitIdle)
+VK_DEVICE_PFN(vkEndCommandBuffer)
+VK_DEVICE_PFN(vkFlushMappedMemoryRanges)
+VK_DEVICE_PFN(vkFreeCommandBuffers)
+VK_DEVICE_PFN(vkFreeDescriptorSets)
+VK_DEVICE_PFN(vkFreeMemory)
+VK_DEVICE_PFN(vkGetBufferMemoryRequirements)
+VK_DEVICE_PFN(vkGetDeviceMemoryCommitment)
+VK_DEVICE_PFN(vkGetDeviceQueue)
+VK_DEVICE_PFN(vkGetEventStatus)
+VK_DEVICE_PFN(vkGetFenceStatus)
+VK_DEVICE_PFN(vkGetImageMemoryRequirements)
+VK_DEVICE_PFN(vkGetImageSparseMemoryRequirements)
+VK_DEVICE_PFN(vkGetImageSubresourceLayout)
+VK_DEVICE_PFN(vkGetPipelineCacheData)
+VK_DEVICE_PFN(vkGetQueryPoolResults)
+VK_DEVICE_PFN(vkGetRenderAreaGranularity)
+VK_DEVICE_PFN(vkInvalidateMappedMemoryRanges)
+VK_DEVICE_PFN(vkMapMemory)
+VK_DEVICE_PFN(vkMergePipelineCaches)
+VK_DEVICE_PFN(vkQueueBindSparse)
+VK_DEVICE_PFN(vkQueueSubmit)
+VK_DEVICE_PFN(vkQueueWaitIdle)
+VK_DEVICE_PFN(vkResetCommandBuffer)
+VK_DEVICE_PFN(vkResetCommandPool)
+VK_DEVICE_PFN(vkResetDescriptorPool)
+VK_DEVICE_PFN(vkResetEvent)
+VK_DEVICE_PFN(vkResetFences)
+VK_DEVICE_PFN(vkSetEvent)
+VK_DEVICE_PFN(vkUnmapMemory)
+VK_DEVICE_PFN(vkUpdateDescriptorSets)
+VK_DEVICE_PFN(vkWaitForFences)
+
+/* VK_KHR_draw_indirect_count */
+VK_DEVICE_EXT_PFN(vkCmdDrawIndirectCountKHR)
+VK_DEVICE_EXT_PFN(vkCmdDrawIndexedIndirectCountKHR)
+
+/* VK_KHR_get_memory_requirements2 */
+VK_DEVICE_EXT_PFN(vkGetBufferMemoryRequirements2KHR)
+VK_DEVICE_EXT_PFN(vkGetImageMemoryRequirements2KHR)
+VK_DEVICE_EXT_PFN(vkGetImageSparseMemoryRequirements2KHR)
+
+/* VK_KHR_maintenance3 */
+VK_DEVICE_EXT_PFN(vkGetDescriptorSetLayoutSupportKHR)
+
+/* VK_KHR_push_descriptor */
+VK_DEVICE_EXT_PFN(vkCmdPushDescriptorSetKHR)
+
+/* VK_EXT_conditional_rendering */
+VK_DEVICE_EXT_PFN(vkCmdBeginConditionalRenderingEXT)
+VK_DEVICE_EXT_PFN(vkCmdEndConditionalRenderingEXT)
+
+/* VK_EXT_debug_marker */
+VK_DEVICE_EXT_PFN(vkDebugMarkerSetObjectNameEXT)
+
+/* VK_EXT_transform_feedback */
+VK_DEVICE_EXT_PFN(vkCmdBeginQueryIndexedEXT)
+VK_DEVICE_EXT_PFN(vkCmdBeginTransformFeedbackEXT)
+VK_DEVICE_EXT_PFN(vkCmdBindTransformFeedbackBuffersEXT)
+VK_DEVICE_EXT_PFN(vkCmdEndQueryIndexedEXT)
+VK_DEVICE_EXT_PFN(vkCmdEndTransformFeedbackEXT)
+
+#undef VK_INSTANCE_PFN
+#undef VK_INSTANCE_EXT_PFN
+#undef VK_DEVICE_PFN
+#undef VK_DEVICE_EXT_PFN
diff --git a/dlls/vkd3d/libvkd3d-wine.spec b/dlls/vkd3d/libvkd3d-wine.spec
new file mode 100644
index 00000000000..93efc2fbb7c
--- /dev/null
+++ b/dlls/vkd3d/libvkd3d-wine.spec
@@ -0,0 +1,20 @@
+@ cdecl vkd3d_acquire_vk_queue(ptr)
+@ cdecl vkd3d_create_device(ptr ptr ptr)
+@ cdecl vkd3d_create_image_resource(ptr ptr ptr)
+@ cdecl vkd3d_create_instance(ptr ptr)
+@ cdecl vkd3d_create_root_signature_deserializer(ptr long ptr ptr)
+@ cdecl vkd3d_create_versioned_root_signature_deserializer(ptr long ptr ptr)
+@ cdecl vkd3d_get_device_parent(ptr)
+@ cdecl vkd3d_get_vk_device(ptr)
+@ cdecl vkd3d_get_vk_format(long)
+@ cdecl vkd3d_get_vk_physical_device(ptr)
+@ cdecl vkd3d_get_vk_queue_family_index(ptr)
+@ cdecl vkd3d_instance_decref(ptr)
+@ cdecl vkd3d_instance_from_device(ptr)
+@ cdecl vkd3d_instance_get_vk_instance(ptr)
+@ cdecl vkd3d_instance_incref(ptr)
+@ cdecl vkd3d_release_vk_queue(ptr)
+@ cdecl vkd3d_resource_decref(ptr)
+@ cdecl vkd3d_resource_incref(ptr)
+@ cdecl vkd3d_serialize_root_signature(ptr long ptr ptr)
+@ cdecl vkd3d_serialize_versioned_root_signature(ptr long ptr ptr)
-- 
2.34.0




More information about the wine-devel mailing list