Procházet zdrojové kódy

Split RenderingDevice into API-agnostic and RenderingDeviceDriver parts

Credit and thanks to @bruzvg for multiple build fixes, update of 3rd-party items and MinGW support.

Co-authored-by: bruvzg <[email protected]>
Pedro J. Estébanez před 1 rokem
rodič
revize
12a519bae2
80 změnil soubory, kde provedl 34695 přidání a 29619 odebrání
  1. 2 1
      core/config/project_settings.cpp
  2. 1 0
      core/typedefs.h
  3. 75 27
      doc/classes/RenderingDevice.xml
  4. 24 12
      drivers/d3d12/SCsub
  5. 148 96
      drivers/d3d12/d3d12_context.cpp
  6. 73 60
      drivers/d3d12/d3d12_context.h
  7. 17 0
      drivers/d3d12/d3d12ma.cpp
  8. 0 9480
      drivers/d3d12/rendering_device_d3d12.cpp
  9. 0 1277
      drivers/d3d12/rendering_device_d3d12.h
  10. 5491 0
      drivers/d3d12/rendering_device_driver_d3d12.cpp
  11. 858 0
      drivers/d3d12/rendering_device_driver_d3d12.h
  12. 2 0
      drivers/vulkan/SCsub
  13. 3350 0
      drivers/vulkan/rendering_device_driver_vulkan.cpp
  14. 482 0
      drivers/vulkan/rendering_device_driver_vulkan.h
  15. 0 9765
      drivers/vulkan/rendering_device_vulkan.cpp
  16. 0 1293
      drivers/vulkan/rendering_device_vulkan.h
  17. 163 144
      drivers/vulkan/vulkan_context.cpp
  18. 47 49
      drivers/vulkan/vulkan_context.h
  19. 2 2
      main/main.cpp
  20. 73 51
      platform/android/display_server_android.cpp
  21. 6 6
      platform/android/display_server_android.h
  22. 6 6
      platform/android/vulkan_context_android.cpp
  23. 5 2
      platform/android/vulkan_context_android.h
  24. 8 6
      platform/ios/display_server_ios.h
  25. 47 35
      platform/ios/display_server_ios.mm
  26. 4 2
      platform/ios/os_ios.h
  27. 4 2
      platform/ios/os_ios.mm
  28. 5 2
      platform/ios/vulkan_context_ios.h
  29. 7 8
      platform/ios/vulkan_context_ios.mm
  30. 55 40
      platform/linuxbsd/x11/display_server_x11.cpp
  31. 7 5
      platform/linuxbsd/x11/display_server_x11.h
  32. 7 7
      platform/linuxbsd/x11/vulkan_context_x11.cpp
  33. 6 2
      platform/linuxbsd/x11/vulkan_context_x11.h
  34. 7 5
      platform/macos/display_server_macos.h
  35. 48 33
      platform/macos/display_server_macos.mm
  36. 5 2
      platform/macos/vulkan_context_macos.h
  37. 6 6
      platform/macos/vulkan_context_macos.mm
  38. 8 4
      platform/windows/detect.py
  39. 74 114
      platform/windows/display_server_windows.cpp
  40. 8 12
      platform/windows/display_server_windows.h
  41. 5 4
      platform/windows/os_windows.h
  42. 8 7
      platform/windows/vulkan_context_win.cpp
  43. 5 1
      platform/windows/vulkan_context_win.h
  44. 33 0
      servers/rendering/renderer_rd/api_context_rd.cpp
  45. 85 0
      servers/rendering/renderer_rd/api_context_rd.h
  46. 6 6
      servers/rendering/renderer_rd/shader_rd.cpp
  47. 2 2
      servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
  48. 6236 835
      servers/rendering/rendering_device.cpp
  49. 587 562
      servers/rendering/rendering_device.h
  50. 1 1
      servers/rendering/rendering_device_binds.h
  51. 912 0
      servers/rendering/rendering_device_commons.cpp
  52. 921 0
      servers/rendering/rendering_device_commons.h
  53. 380 0
      servers/rendering/rendering_device_driver.cpp
  54. 687 0
      servers/rendering/rendering_device_driver.h
  55. 10 1
      thirdparty/README.md
  56. 24 0
      thirdparty/d3d12ma/D3D12MemAlloc.cpp
  57. 0 5459
      thirdparty/directx_headers/d3dx12.h
  58. 2627 0
      thirdparty/directx_headers/include/directx/D3D12TokenizedProgramFormat.hpp
  59. 2944 142
      thirdparty/directx_headers/include/directx/d3d12.h
  60. 0 0
      thirdparty/directx_headers/include/directx/d3d12compatibility.h
  61. 134 15
      thirdparty/directx_headers/include/directx/d3d12sdklayers.h
  62. 0 0
      thirdparty/directx_headers/include/directx/d3d12shader.h
  63. 645 28
      thirdparty/directx_headers/include/directx/d3d12video.h
  64. 1 0
      thirdparty/directx_headers/include/directx/d3dcommon.h
  65. 35 0
      thirdparty/directx_headers/include/directx/d3dx12.h
  66. 192 0
      thirdparty/directx_headers/include/directx/d3dx12_barriers.h
  67. 1107 0
      thirdparty/directx_headers/include/directx/d3dx12_check_feature_support.h
  68. 1535 0
      thirdparty/directx_headers/include/directx/d3dx12_core.h
  69. 12 0
      thirdparty/directx_headers/include/directx/d3dx12_default.h
  70. 1411 0
      thirdparty/directx_headers/include/directx/d3dx12_pipeline_state_stream.h
  71. 124 0
      thirdparty/directx_headers/include/directx/d3dx12_property_format_table.h
  72. 102 0
      thirdparty/directx_headers/include/directx/d3dx12_render_pass.h
  73. 602 0
      thirdparty/directx_headers/include/directx/d3dx12_resource_helpers.h
  74. 1204 0
      thirdparty/directx_headers/include/directx/d3dx12_root_signature.h
  75. 790 0
      thirdparty/directx_headers/include/directx/d3dx12_state_object.h
  76. 0 0
      thirdparty/directx_headers/include/directx/dxcore.h
  77. 0 0
      thirdparty/directx_headers/include/directx/dxcore_interface.h
  78. 0 0
      thirdparty/directx_headers/include/directx/dxgicommon.h
  79. 2 0
      thirdparty/directx_headers/include/directx/dxgiformat.h
  80. 195 0
      thirdparty/directx_headers/include/dxguids/dxguids.h

+ 2 - 1
core/config/project_settings.cpp

@@ -95,7 +95,7 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
 	features.append(VERSION_FULL_CONFIG);
 	features.append(VERSION_FULL_BUILD);
 
-#if defined(VULKAN_ENABLED) || defined(D3D12_ENABLED)
+#ifdef RD_ENABLED
 	features.append("Forward Plus");
 	features.append("Mobile");
 #endif
@@ -1399,6 +1399,7 @@ ProjectSettings::ProjectSettings() {
 	GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
 	GLOBAL_DEF("rendering/rendering_device/pipeline_cache/save_chunk_size_mb", 3.0);
 	GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+
 	GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", 16384);
 	custom_prop_info["rendering/rendering_device/d3d12/max_resource_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", PROPERTY_HINT_RANGE, "512,262144");
 	GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", 1024);

+ 1 - 0
core/typedefs.h

@@ -92,6 +92,7 @@
 #undef Error
 #undef OK
 #undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
+#undef MemoryBarrier
 #endif
 
 // Make room for our constexpr's below by overriding potential system-specific macros.

+ 75 - 27
doc/classes/RenderingDevice.xml

@@ -796,12 +796,13 @@
 				Returns the data format used to create this texture.
 			</description>
 		</method>
-		<method name="texture_get_native_handle">
+		<method name="texture_get_native_handle" is_deprecated="true">
 			<return type="int" />
 			<param index="0" name="texture" type="RID" />
 			<description>
 				Returns the internal graphics handle for this texture object. For use when communicating with third-party APIs mostly with GDExtension.
 				[b]Note:[/b] This function returns a [code]uint64_t[/code] which internally maps to a [code]GLuint[/code] (OpenGL) or [code]VkImage[/code] (Vulkan).
+				[i]Deprecated.[/i] Use [method get_driver_resource] with [constant DRIVER_RESOURCE_TEXTURE] instead.
 			</description>
 		</method>
 		<method name="texture_is_format_supported_for_usage" qualifiers="const">
@@ -928,44 +929,91 @@
 		<constant name="DEVICE_TYPE_MAX" value="5" enum="DeviceType">
 			Represents the size of the [enum DeviceType] enum.
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_DEVICE" value="0" enum="DriverResource">
-			Vulkan device driver resource. This is a "global" resource and ignores the RID passed in
+		<constant name="DRIVER_RESOURCE_LOGICAL_DEVICE" value="0" enum="DriverResource">
+			Specific device object based on a physical device.
+			- Vulkan: Vulkan device driver resource ([code]VkDevice[/code]). ([code]rid[/code] argument doesn't apply.)
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE" value="1" enum="DriverResource">
-			Physical device (graphics card) driver resource.
+		<constant name="DRIVER_RESOURCE_PHYSICAL_DEVICE" value="1" enum="DriverResource">
+			Physical device the specific logical device is based on.
+			- Vulkan: [code]VkDevice[/code]. ([code]rid[/code] argument doesn't apply.)
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_INSTANCE" value="2" enum="DriverResource">
-			Vulkan instance driver resource.
+		<constant name="DRIVER_RESOURCE_TOPMOST_OBJECT" value="2" enum="DriverResource">
+			Top-most graphics API entry object.
+			- Vulkan: [code]VkInstance[/code]. ([code]rid[/code] argument doesn't apply.)
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_QUEUE" value="3" enum="DriverResource">
-			Vulkan queue driver resource.
+		<constant name="DRIVER_RESOURCE_COMMAND_QUEUE" value="3" enum="DriverResource">
+			The main graphics-compute command queue.
+			- Vulkan: [code]VkQueue[/code]. ([code]rid[/code] argument doesn't apply.)
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX" value="4" enum="DriverResource">
-			Vulkan queue family index driver resource.
+		<constant name="DRIVER_RESOURCE_QUEUE_FAMILY" value="4" enum="DriverResource">
+			The specific family the main queue belongs to.
+			- Vulkan: the queue family index, an [code]uint32_t[/code]. ([code]rid[/code] argument doesn't apply.)
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE" value="5" enum="DriverResource">
-			Vulkan image driver resource.
+		<constant name="DRIVER_RESOURCE_TEXTURE" value="5" enum="DriverResource">
+			- Vulkan: [code]VkImage[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE_VIEW" value="6" enum="DriverResource">
-			Vulkan image view driver resource.
+		<constant name="DRIVER_RESOURCE_TEXTURE_VIEW" value="6" enum="DriverResource">
+			The view of an owned or shared texture.
+			- Vulkan: [code]VkImageView[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT" value="7" enum="DriverResource">
-			Vulkan image native texture format driver resource.
+		<constant name="DRIVER_RESOURCE_TEXTURE_DATA_FORMAT" value="7" enum="DriverResource">
+			The native id of the data format of the texture.
+			- Vulkan: [code]VkFormat[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_SAMPLER" value="8" enum="DriverResource">
-			Vulkan sampler driver resource.
+		<constant name="DRIVER_RESOURCE_SAMPLER" value="8" enum="DriverResource">
+			- Vulkan: [code]VkSampler[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET" value="9" enum="DriverResource">
-			Vulkan [url=https://vkguide.dev/docs/chapter-4/descriptors/]descriptor set[/url] driver resource.
+		<constant name="DRIVER_RESOURCE_UNIFORM_SET" value="9" enum="DriverResource">
+			- Vulkan: [code]VkDescriptorSet[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_BUFFER" value="10" enum="DriverResource">
-			Vulkan buffer driver resource.
+		<constant name="DRIVER_RESOURCE_BUFFER" value="10" enum="DriverResource">
+			Buffer of any kind of (storage, vertex, etc.).
+			- Vulkan: [code]VkBuffer[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE" value="11" enum="DriverResource">
-			Vulkan compute pipeline driver resource.
+		<constant name="DRIVER_RESOURCE_COMPUTE_PIPELINE" value="11" enum="DriverResource">
+			- Vulkan: [code]VkPipeline[/code].
 		</constant>
-		<constant name="DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE" value="12" enum="DriverResource">
-			Vulkan render pipeline driver resource.
+		<constant name="DRIVER_RESOURCE_RENDER_PIPELINE" value="12" enum="DriverResource">
+			- Vulkan: [code]VkPipeline[/code].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_DEVICE" value="0" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_LOGICAL_DEVICE].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE" value="1" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_PHYSICAL_DEVICE].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_INSTANCE" value="2" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TOPMOST_OBJECT].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_QUEUE" value="3" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_COMMAND_QUEUE].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX" value="4" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_QUEUE_FAMILY].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE" value="5" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE_VIEW" value="6" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE_VIEW].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT" value="7" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE_DATA_FORMAT].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_SAMPLER" value="8" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_SAMPLER].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET" value="9" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_UNIFORM_SET].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_BUFFER" value="10" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_BUFFER].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE" value="11" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_COMPUTE_PIPELINE].
+		</constant>
+		<constant name="DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE" value="12" enum="DriverResource" is_deprecated="true">
+			[i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_RENDER_PIPELINE].
 		</constant>
 		<constant name="DATA_FORMAT_R4G4_UNORM_PACK8" value="0" enum="DataFormat">
 			4-bit-per-channel red/green channel data format, packed into 8 bits. Values are in the [code][0.0, 1.0][/code] range.

+ 24 - 12
drivers/d3d12/SCsub

@@ -5,36 +5,39 @@ from pathlib import Path
 
 Import("env")
 
-env_d3d12_rd = env.Clone()
+env.Append(CPPDEFINES=["RD_ENABLED"])
+
+env_d3d12_rdd = env.Clone()
 
 thirdparty_obj = []
 
 
 # DirectX Headers (must take precedence over Windows SDK's).
 
-env.Prepend(CPPPATH=["#thirdparty/directx_headers"])
-env_d3d12_rd.Prepend(CPPPATH=["#thirdparty/directx_headers"])
+env.Prepend(CPPPATH=["#thirdparty/directx_headers/include/directx"])
+env_d3d12_rdd.Prepend(CPPPATH=["#thirdparty/directx_headers/include/directx"])
+env_d3d12_rdd.Prepend(CPPPATH=["#thirdparty/directx_headers/include/dxguids"])
 
 
 # Direct3D 12 Memory Allocator.
 
 env.Append(CPPPATH=["#thirdparty/d3d12ma"])
-env_d3d12_rd.Append(CPPPATH=["#thirdparty/d3d12ma"])
+env_d3d12_rdd.Append(CPPPATH=["#thirdparty/d3d12ma"])
 
 
 # Agility SDK.
 
 if env["agility_sdk_path"] != "":
-    env_d3d12_rd.Append(CPPDEFINES=["AGILITY_SDK_ENABLED"])
+    env_d3d12_rdd.Append(CPPDEFINES=["AGILITY_SDK_ENABLED"])
     if env["agility_sdk_multiarch"]:
-        env_d3d12_rd.Append(CPPDEFINES=["AGILITY_SDK_MULTIARCH_ENABLED"])
+        env_d3d12_rdd.Append(CPPDEFINES=["AGILITY_SDK_MULTIARCH_ENABLED"])
 
 
 # PIX.
 
 if env["pix_path"] != "":
-    env_d3d12_rd.Append(CPPDEFINES=["PIX_ENABLED"])
-    env_d3d12_rd.Append(CPPPATH=[env["pix_path"] + "/Include"])
+    env_d3d12_rdd.Append(CPPDEFINES=["PIX_ENABLED"])
+    env_d3d12_rdd.Append(CPPPATH=[env["pix_path"] + "/Include"])
 
 
 # Mesa (SPIR-V to DXIL functionality).
@@ -105,12 +108,16 @@ extra_defines = [
     "WINDOWS_NO_FUTEX",
 ]
 
+mesa_ver = Path(mesa_absdir + "/VERSION.info")
+if not mesa_ver.is_file():
+    mesa_ver = Path(mesa_absdir + "/VERSION")
+
 # These defines are inspired by the Meson build scripts in the original repo.
 extra_defines += [
     "__STDC_CONSTANT_MACROS",
     "__STDC_FORMAT_MACROS",
     "__STDC_LIMIT_MACROS",
-    ("PACKAGE_VERSION", '\\"' + Path(mesa_absdir + "/VERSION").read_text().strip() + '\\"'),
+    ("PACKAGE_VERSION", '\\"' + mesa_ver.read_text().strip() + '\\"'),
     ("PACKAGE_BUGREPORT", '\\"https://gitlab.freedesktop.org/mesa/mesa/-/issues\\"'),
     "PIPE_SUBSYSTEM_WINDOWS_USER",
     ("_Static_assert", "static_assert"),
@@ -129,11 +136,16 @@ if env.msvc:
         "NOMINMAX",
         "HAVE_STRUCT_TIMESPEC",
     ]
+else:
+    extra_defines += [
+        ("__REQUIRED_RPCNDR_H_VERSION__", 475),
+        "HAVE_STRUCT_TIMESPEC",
+    ]
 
 # This is needed since rendering_device_d3d12.cpp needs to include some Mesa internals.
-env_d3d12_rd.Prepend(CPPPATH=mesa_private_inc_paths)
+env_d3d12_rdd.Prepend(CPPPATH=mesa_private_inc_paths)
 # For the same reason as above, the defines must be the same as in the 3rd-party code itself.
-env_d3d12_rd.Append(CPPDEFINES=extra_defines)
+env_d3d12_rdd.Append(CPPDEFINES=extra_defines)
 
 
 # Add all.
@@ -144,7 +156,7 @@ env.drivers_sources += thirdparty_obj
 # Godot source files.
 
 driver_obj = []
-env_d3d12_rd.add_source_files(driver_obj, "*.cpp")
+env_d3d12_rdd.add_source_files(driver_obj, "*.cpp")
 env.drivers_sources += driver_obj
 
 # Needed to force rebuilding the driver files when the thirdparty code is updated.

+ 148 - 96
drivers/d3d12/d3d12_context.cpp

@@ -37,8 +37,26 @@
 #include "core/version.h"
 #include "servers/rendering/rendering_device.h"
 
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
 #include "dxcapi.h"
 
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#if !defined(_MSC_VER)
+#include <guiddef.h>
+
+#include <dxguids.h>
+#endif
+
 extern "C" {
 char godot_nir_arch_name[32];
 
@@ -47,8 +65,12 @@ __declspec(dllexport) extern const UINT D3D12SDKVersion = 610;
 #ifdef AGILITY_SDK_MULTIARCH_ENABLED
 #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
 __declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\arm64";
-#else
+#elif defined(__arm__) || defined(_M_ARM)
+__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\arm32";
+#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
 __declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\x86_64";
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+__declspec(dllexport) extern const char *D3D12SDKPath = "\\.\\x86_32";
 #endif
 #else
 __declspec(dllexport) extern const char *D3D12SDKPath = "\\.";
@@ -57,11 +79,15 @@ __declspec(dllexport) extern const char *D3D12SDKPath = "\\.";
 }
 
 #ifdef PIX_ENABLED
+#if defined(__GNUC__)
+#define _MSC_VER 1800
+#endif
 #define USE_PIX
 #include "WinPixEventRuntime/pix3.h"
+#if defined(__GNUC__)
+#undef _MSC_VER
+#endif
 #endif
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
 void D3D12Context::_debug_message_func(
 		D3D12_MESSAGE_CATEGORY p_category,
@@ -178,7 +204,7 @@ Error D3D12Context::_check_capabilities() {
 		D3D12_FEATURE_DATA_SHADER_MODEL shader_model = {};
 		shader_model.HighestShaderModel = MIN(D3D_HIGHEST_SHADER_MODEL, D3D_SHADER_MODEL_6_6);
 		HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model));
-		ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 		shader_capabilities.shader_model = shader_model.HighestShaderModel;
 	}
 	print_verbose("- Shader:");
@@ -270,7 +296,7 @@ Error D3D12Context::_check_capabilities() {
 Error D3D12Context::_initialize_debug_layers() {
 	ComPtr<ID3D12Debug> debug_controller;
 	HRESULT res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller));
-	ERR_FAIL_COND_V(res, ERR_QUERY_FAILED);
+	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED);
 	debug_controller->EnableDebugLayer();
 	return OK;
 }
@@ -399,7 +425,7 @@ Error D3D12Context::_select_adapter(int &r_index) {
 		if (SUCCEEDED(res)) {
 			tearing_supported = result;
 		} else {
-			ERR_PRINT("CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
+			ERR_PRINT("CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 		}
 	}
 
@@ -423,7 +449,7 @@ void D3D12Context::_dump_adapter_info(int p_index) {
 		feat_levels.pFeatureLevelsRequested = FEATURE_LEVELS;
 
 		HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feat_levels, sizeof(feat_levels));
-		ERR_FAIL_COND_MSG(res, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
+		ERR_FAIL_COND_MSG(!SUCCEEDED(res), "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 
 		// Example: D3D_FEATURE_LEVEL_12_1 = 0xc100.
 		uint32_t feat_level_major = feat_levels.MaxSupportedFeatureLevel >> 12;
@@ -476,25 +502,25 @@ void D3D12Context::_dump_adapter_info(int p_index) {
 
 Error D3D12Context::_create_device(DeviceBasics &r_basics) {
 	HRESULT res = D3D12CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf()));
-	ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", res) + ".");
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 
 	// Create direct command queue.
 	D3D12_COMMAND_QUEUE_DESC queue_desc = {};
 	queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
 	queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
 	res = r_basics.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(r_basics.queue.GetAddressOf()));
-	ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 
 	// Create sync objects.
 	res = r_basics.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(r_basics.fence.GetAddressOf()));
-	ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 	r_basics.fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
 	ERR_FAIL_NULL_V(r_basics.fence_event, ERR_CANT_CREATE);
 
 	if (_use_validation_layers()) {
 		ComPtr<ID3D12InfoQueue> info_queue;
 		res = r_basics.device.As(&info_queue);
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 
 #if 0 // This causes crashes. Needs investigation.
 		ComPtr<ID3D12InfoQueue1> info_queue_1;
@@ -505,7 +531,7 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) {
 			info_queue_1->SetMuteDebugOutput(TRUE);
 
 			res = info_queue_1->RegisterMessageCallback(&_debug_message_func, D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS, nullptr, 0);
-			ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+			ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 		} else
 #endif
 		{
@@ -513,7 +539,11 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) {
 
 			if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) {
 				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
-				ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
+				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
+				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 			}
 		}
 		D3D12_MESSAGE_SEVERITY severities_to_mute[] = {
@@ -535,7 +565,7 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) {
 		filter.DenyList.pIDList = messages_to_mute;
 
 		res = info_queue->PushStorageFilter(&filter);
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 	}
 
 	return OK;
@@ -544,7 +574,7 @@ Error D3D12Context::_create_device(DeviceBasics &r_basics) {
 Error D3D12Context::_get_device_limits() {
 	D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
 	HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
-	ERR_FAIL_COND_V_MSG(res, ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 
 	// https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
 	gpu_limits.max_srvs_per_shader_stage = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 128 : UINT64_MAX;
@@ -567,18 +597,44 @@ bool D3D12Context::_use_validation_layers() {
 	return Engine::get_singleton()->is_validation_layers_enabled();
 }
 
-Error D3D12Context::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
+Error D3D12Context::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
 	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
 
 	Window window;
-	window.hwnd = p_window;
+	window.hwnd = ((const WindowPlatformData *)p_platform_data)->window;
 	window.width = p_width;
 	window.height = p_height;
 	window.vsync_mode = p_vsync_mode;
+
+	{
+		RDD::Attachment attachment;
+		attachment.samples = RD::TEXTURE_SAMPLES_1;
+		attachment.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
+		attachment.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+		window.render_pass.attachments.push_back(attachment);
+
+		RDD::Subpass subpass;
+		{
+			RDD::AttachmentReference color_ref;
+			color_ref.attachment = 0;
+			color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
+			subpass.color_references.push_back(color_ref);
+		}
+		window.render_pass.subpasses.push_back(subpass);
+	}
+
+	for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
+		Error err = window.framebuffers[i].rtv_heap.allocate(md.device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1, false);
+		ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+		window.framebuffers[i].is_screen = true;
+		window.framebuffers[i].attachments_handle_inds.push_back(0);
+	}
+
 	Error err = _update_swap_chain(&window);
 	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
 
 	windows[p_window_id] = window;
+
 	return OK;
 }
 
@@ -605,25 +661,20 @@ bool D3D12Context::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
 	return (bool)w->swapchain;
 }
 
-CD3DX12_CPU_DESCRIPTOR_HANDLE D3D12Context::window_get_framebuffer_rtv_handle(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT()));
-	ERR_FAIL_COND_V(!buffers_prepared, CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT()));
+RDD::RenderPassID D3D12Context::window_get_render_pass(DisplayServer::WindowID p_window) {
+	ERR_FAIL_COND_V(!windows.has(p_window), RDD::RenderPassID());
 	Window *w = &windows[p_window];
-	CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(
-			w->rtv_heap->GetCPUDescriptorHandleForHeapStart(),
-			w->current_buffer,
-			md.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
-	return rtv_handle;
+	return RDD::RenderPassID(&w->render_pass);
 }
 
-ID3D12Resource *D3D12Context::window_get_framebuffer_texture(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), nullptr);
-	ERR_FAIL_COND_V(!buffers_prepared, nullptr);
+RDD::FramebufferID D3D12Context::window_get_framebuffer(DisplayServer::WindowID p_window) {
+	ERR_FAIL_COND_V(!windows.has(p_window), RDD::FramebufferID());
+	ERR_FAIL_COND_V(!buffers_prepared, RDD::FramebufferID());
 	Window *w = &windows[p_window];
 	if (w->swapchain) {
-		return w->render_targets[w->current_buffer].Get();
+		return RDD::FramebufferID(&w->framebuffers[w->current_buffer]);
 	} else {
-		return nullptr;
+		return RDD::FramebufferID();
 	}
 }
 
@@ -699,7 +750,6 @@ Error D3D12Context::_update_swap_chain(Window *window) {
 		for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
 			window->render_targets[i].Reset();
 		}
-		window->rtv_heap.Reset();
 
 		// D3D12 docs: "IDXGISwapChain::ResizeBuffers can't be used to add or remove this flag."
 		bool allow_tearing_flag_changed = (swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) != (window->swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
@@ -722,45 +772,37 @@ Error D3D12Context::_update_swap_chain(Window *window) {
 
 		ComPtr<IDXGISwapChain1> swapchain;
 		HRESULT res = dxgi_factory->CreateSwapChainForHwnd(md.queue.Get(), window->hwnd, &swapchain_desc, nullptr, nullptr, swapchain.GetAddressOf());
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 		swapchain.As(&window->swapchain);
 		ERR_FAIL_NULL_V(window->swapchain, ERR_CANT_CREATE);
 
 		format = swapchain_desc.Format;
 
 		res = dxgi_factory->MakeWindowAssociation(window->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 
 		res = window->swapchain->GetDesc1(&swapchain_desc);
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 		ERR_FAIL_COND_V(swapchain_desc.BufferCount != IMAGE_COUNT, ERR_BUG);
 		window->width = swapchain_desc.Width;
 		window->height = swapchain_desc.Height;
 
 	} else {
 		HRESULT res = window->swapchain->ResizeBuffers(IMAGE_COUNT, window->width, window->height, DXGI_FORMAT_UNKNOWN, swapchain_flags);
-		ERR_FAIL_COND_V(res, ERR_UNAVAILABLE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);
 	}
 
 	window->swapchain_flags = swapchain_flags;
 	window->current_buffer = window->swapchain->GetCurrentBackBufferIndex();
 
-	// Describe and create a render target view (RTV) descriptor heap.
-	D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = {};
-	rtv_heap_desc.NumDescriptors = IMAGE_COUNT;
-	rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
-	rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
-	HRESULT res = md.device->CreateDescriptorHeap(&rtv_heap_desc, IID_PPV_ARGS(window->rtv_heap.GetAddressOf()));
-	ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
-
-	CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(window->rtv_heap->GetCPUDescriptorHandleForHeapStart());
-
 	for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
-		res = window->swapchain->GetBuffer(i, IID_PPV_ARGS(&window->render_targets[i]));
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		RenderingDeviceDriverD3D12::FramebufferInfo *fb_info = &window->framebuffers[i];
+		RenderingDeviceDriverD3D12::DescriptorsHeap::Walker walker = fb_info->rtv_heap.make_walker();
+
+		HRESULT res = window->swapchain->GetBuffer(i, IID_PPV_ARGS(&window->render_targets[i]));
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 
-		md.device->CreateRenderTargetView(window->render_targets[i].Get(), nullptr, rtv_handle);
-		rtv_handle.Offset(1, md.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
+		md.device->CreateRenderTargetView(window->render_targets[i].Get(), nullptr, walker.get_curr_cpu_handle());
 	}
 
 	return OK;
@@ -790,33 +832,28 @@ Error D3D12Context::initialize() {
 
 	{
 		HRESULT res = md.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(frame_fence.GetAddressOf()));
-		ERR_FAIL_COND_V(res, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
 		frame_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
 		ERR_FAIL_NULL_V(frame_fence_event, ERR_CANT_CREATE);
 	}
 
-	{ // Initialize allocator.
-		D3D12MA::ALLOCATOR_DESC allocator_desc = {};
-		allocator_desc.pDevice = md.device.Get();
-		allocator_desc.pAdapter = gpu.Get();
-
-		HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator);
-		ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", res) + ".");
-	}
+	md.driver = memnew(RenderingDeviceDriverD3D12(this, md.device.Get(), IMAGE_COUNT + 1));
 
 	return OK;
 }
 
-void D3D12Context::set_setup_list(ID3D12CommandList *p_command_list) {
-	command_list_queue.write[0] = p_command_list;
+void D3D12Context::set_setup_buffer(RDD::CommandBufferID p_command_buffer) {
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	command_list_queue[0] = cmd_buf_info->cmd_list.Get();
 }
 
-void D3D12Context::append_command_list(ID3D12CommandList *p_command_list) {
+void D3D12Context::append_command_buffer(RDD::CommandBufferID p_command_buffer) {
 	if (command_list_queue.size() <= command_list_count) {
 		command_list_queue.resize(command_list_count + 1);
 	}
 
-	command_list_queue.write[command_list_count] = p_command_list;
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	command_list_queue[command_list_count] = cmd_buf_info->cmd_list.Get();
 	command_list_count++;
 }
 
@@ -833,7 +870,7 @@ void D3D12Context::_wait_for_idle_queue(ID3D12CommandQueue *p_queue) {
 void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending) {
 	if (p_flush_setup && command_list_queue[0]) {
 		md.queue->ExecuteCommandLists(1, command_list_queue.ptr());
-		command_list_queue.write[0] = nullptr;
+		command_list_queue[0] = nullptr;
 	}
 
 	if (p_flush_pending && command_list_count > 1) {
@@ -846,7 +883,7 @@ void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending) {
 	}
 }
 
-void D3D12Context::prepare_buffers(ID3D12GraphicsCommandList *p_command_list) {
+Error D3D12Context::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
 	// Ensure no more than FRAME_LAG renderings are outstanding.
 	if (frame >= IMAGE_COUNT) {
 		UINT64 min_value = frame - IMAGE_COUNT;
@@ -860,20 +897,21 @@ void D3D12Context::prepare_buffers(ID3D12GraphicsCommandList *p_command_list) {
 	}
 
 	D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
-
 	uint32_t n = 0;
 	for (KeyValue<int, Window> &E : windows) {
 		Window *w = &E.value;
 		w->current_buffer = w->swapchain->GetCurrentBackBufferIndex();
 		barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
 	}
-
-	p_command_list->ResourceBarrier(n, barriers);
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
 
 	buffers_prepared = true;
+
+	return OK;
 }
 
-void D3D12Context::postpare_buffers(ID3D12GraphicsCommandList *p_command_list) {
+void D3D12Context::postpare_buffers(RDD::CommandBufferID p_command_buffer) {
 	D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
 
 	uint32_t n = 0;
@@ -882,7 +920,8 @@ void D3D12Context::postpare_buffers(ID3D12GraphicsCommandList *p_command_list) {
 		barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
 	}
 
-	p_command_list->ResourceBarrier(n, barriers);
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
 }
 
 Error D3D12Context::swap_buffers() {
@@ -902,7 +941,7 @@ Error D3D12Context::swap_buffers() {
 
 	md.queue->ExecuteCommandLists(commands_to_submit, commands_ptr);
 
-	command_list_queue.write[0] = nullptr;
+	command_list_queue[0] = nullptr;
 	command_list_count = 1;
 
 	for (KeyValue<int, Window> &E : windows) {
@@ -912,8 +951,8 @@ Error D3D12Context::swap_buffers() {
 			continue;
 		}
 		HRESULT res = w->swapchain->Present(w->sync_interval, w->present_flags);
-		if (res) {
-			print_verbose("D3D12: Presenting swapchain of window " + itos(E.key) + " failed with error " + vformat("0x%08ux", res) + ".");
+		if (!SUCCEEDED(res)) {
+			print_verbose("D3D12: Presenting swapchain of window " + itos(E.key) + " failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
 		}
 	}
 
@@ -927,16 +966,20 @@ Error D3D12Context::swap_buffers() {
 void D3D12Context::resize_notify() {
 }
 
-ComPtr<ID3D12Device> D3D12Context::get_device() {
-	return md.device;
+RenderingDevice::Capabilities D3D12Context::get_device_capabilities() const {
+	RenderingDevice::Capabilities c;
+	c.device_family = RenderingDevice::DEVICE_DIRECTX;
+	c.version_major = feature_level / 10;
+	c.version_minor = feature_level % 10;
+	return c;
 }
 
-ComPtr<IDXGIAdapter> D3D12Context::get_adapter() {
-	return gpu;
+ID3D12Device *D3D12Context::get_device() {
+	return md.device.Get();
 }
 
-D3D12MA::Allocator *D3D12Context::get_allocator() {
-	return allocator.Get();
+IDXGIAdapter *D3D12Context::get_adapter() {
+	return gpu.Get();
 }
 
 int D3D12Context::get_swapchain_image_count() const {
@@ -947,26 +990,22 @@ DXGI_FORMAT D3D12Context::get_screen_format() const {
 	return format;
 }
 
-D3D12Context::DeviceLimits D3D12Context::get_device_limits() const {
+const D3D12Context::DeviceLimits &D3D12Context::get_device_limits() const {
 	return gpu_limits;
 }
 
 RID D3D12Context::local_device_create() {
 	LocalDevice ld;
 	_create_device(ld);
+	ld.driver = memnew(RenderingDeviceDriverD3D12(this, ld.device.Get(), 1));
 	return local_device_owner.make_rid(ld);
 }
 
-ComPtr<ID3D12Device> D3D12Context::local_device_get_d3d12_device(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	return ld->device;
-}
-
-void D3D12Context::local_device_push_command_lists(RID p_local_device, ID3D12CommandList *const *p_lists, int p_count) {
+void D3D12Context::local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) {
 	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
 	ERR_FAIL_COND(ld->waiting);
 
-	ld->queue->ExecuteCommandLists(p_count, p_lists);
+	ld->queue->ExecuteCommandLists(p_count, (ID3D12CommandList *const *)p_buffers);
 
 	ld->waiting = true;
 }
@@ -988,27 +1027,29 @@ void D3D12Context::local_device_sync(RID p_local_device) {
 
 void D3D12Context::local_device_free(RID p_local_device) {
 	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-
+	memdelete(ld->driver);
 	CloseHandle(ld->fence_event);
-
 	local_device_owner.free(p_local_device);
 }
 
-void D3D12Context::command_begin_label(ID3D12GraphicsCommandList *p_command_list, String p_label_name, const Color p_color) {
+void D3D12Context::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
 #ifdef PIX_ENABLED
-	PIXBeginEvent(p_command_list, p_color.to_argb32(), p_label_name.utf8().get_data());
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data());
 #endif
 }
 
-void D3D12Context::command_insert_label(ID3D12GraphicsCommandList *p_command_list, String p_label_name, const Color p_color) {
+void D3D12Context::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
 #ifdef PIX_ENABLED
-	PIXSetMarker(p_command_list, p_color.to_argb32(), p_label_name.utf8().get_data());
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	PIXSetMarker(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name.utf8().get_data());
 #endif
 }
 
-void D3D12Context::command_end_label(ID3D12GraphicsCommandList *p_command_list) {
+void D3D12Context::command_end_label(RDD::CommandBufferID p_command_buffer) {
 #ifdef PIX_ENABLED
-	PIXEndEvent(p_command_list);
+	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
+	PIXEndEvent(cmd_buf_info->cmd_list.Get());
 #endif
 }
 
@@ -1050,11 +1091,22 @@ void D3D12Context::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServe
 	_update_swap_chain(&windows[p_window]);
 }
 
+RenderingDeviceDriver *D3D12Context::get_driver(RID p_local_device) {
+	if (p_local_device.is_valid()) {
+		LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
+		ERR_FAIL_NULL_V(ld, nullptr);
+		return ld->driver;
+	} else {
+		return md.driver;
+	}
+}
+
 D3D12Context::D3D12Context() {
 	command_list_queue.resize(1); // First one is always the setup command.
-	command_list_queue.write[0] = nullptr;
+	command_list_queue[0] = nullptr;
 
-	strcpy(godot_nir_arch_name, Engine::get_singleton()->get_architecture_name().ascii().get_data());
+	CharString cs = Engine::get_singleton()->get_architecture_name().ascii();
+	memcpy(godot_nir_arch_name, (const char *)cs.get_data(), cs.size());
 }
 
 D3D12Context::~D3D12Context() {

+ 73 - 60
drivers/d3d12/d3d12_context.h

@@ -34,20 +34,38 @@
 #include "core/error/error_list.h"
 #include "core/os/mutex.h"
 #include "core/string/ustring.h"
-#include "core/templates/rb_map.h"
 #include "core/templates/rid_owner.h"
+#include "rendering_device_driver_d3d12.h"
 #include "servers/display_server.h"
-#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/renderer_rd/api_context_rd.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif
+
+#if defined(AS)
+#undef AS
+#endif
 
 #include "d3dx12.h"
 #include <dxgi1_6.h>
-#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
-#include "D3D12MemAlloc.h"
 
 #include <wrl/client.h>
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
 using Microsoft::WRL::ComPtr;
 
-class D3D12Context {
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+class D3D12Context : public ApiContextRD {
 public:
 	struct DeviceLimits {
 		uint64_t max_srvs_per_shader_stage;
@@ -64,15 +82,6 @@ public:
 		uint32_t supported_operations_flags_rd() const;
 	};
 
-	// Following VulkanContext definition.
-	struct MultiviewCapabilities {
-		bool is_supported;
-		bool geometry_shader_is_supported;
-		bool tessellation_shader_is_supported;
-		uint32_t max_view_count;
-		uint32_t max_instance_count;
-	};
-
 	struct VRSCapabilities {
 		bool draw_call_supported; // We can specify our fragment rate on a draw call level.
 		bool primitive_supported; // We can specify our fragment rate on each drawcall.
@@ -110,12 +119,13 @@ private:
 		ComPtr<ID3D12Fence> fence;
 		HANDLE fence_event = nullptr;
 		UINT64 fence_value = 0;
+		RenderingDeviceDriverD3D12 *driver = nullptr;
 	} md; // 'Main device', as opposed to local device.
 
 	uint32_t feature_level = 0; // Major * 10 + minor.
 	bool tearing_supported = false;
 	SubgroupCapabilities subgroup_capabilities;
-	MultiviewCapabilities multiview_capabilities;
+	RDD::MultiviewCapabilities multiview_capabilities;
 	VRSCapabilities vrs_capabilities;
 	ShaderCapabilities shader_capabilities;
 	StorageBufferCapabilities storage_buffer_capabilities;
@@ -126,8 +136,6 @@ private:
 	RenderingDevice::DeviceType adapter_type = {};
 	String pipeline_cache_id;
 
-	ComPtr<D3D12MA::Allocator> allocator;
-
 	bool buffers_prepared = false;
 
 	DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
@@ -146,7 +154,8 @@ private:
 		int width = 0;
 		int height = 0;
 		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
-		ComPtr<ID3D12DescriptorHeap> rtv_heap;
+		RenderingDeviceDriverD3D12::RenderPassInfo render_pass;
+		RenderingDeviceDriverD3D12::FramebufferInfo framebuffers[IMAGE_COUNT];
 	};
 
 	struct LocalDevice : public DeviceBasics {
@@ -161,8 +170,8 @@ private:
 
 	// Commands.
 
-	Vector<ID3D12CommandList *> command_list_queue;
-	int command_list_count = 1;
+	LocalVector<ID3D12CommandList *> command_list_queue;
+	uint32_t command_list_count = 1;
 
 	static void _debug_message_func(
 			D3D12_MESSAGE_CATEGORY p_category,
@@ -187,59 +196,63 @@ protected:
 	virtual bool _use_validation_layers();
 
 public:
-	uint32_t get_feat_level_major() const { return feature_level / 10; };
-	uint32_t get_feat_level_minor() const { return feature_level % 10; };
+	virtual const char *get_api_name() const override final { return "D3D12"; };
+	virtual RenderingDevice::Capabilities get_device_capabilities() const override final;
 	const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
-	const MultiviewCapabilities &get_multiview_capabilities() const { return multiview_capabilities; };
+	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const override final { return multiview_capabilities; };
 	const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
 	const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
 	const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
 	const FormatCapabilities &get_format_capabilities() const { return format_capabilities; };
 
-	ComPtr<ID3D12Device> get_device();
-	ComPtr<IDXGIAdapter> get_adapter();
-	D3D12MA::Allocator *get_allocator();
-	int get_swapchain_image_count() const;
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
-	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
-	int window_get_width(DisplayServer::WindowID p_window = 0);
-	int window_get_height(DisplayServer::WindowID p_window = 0);
-	bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0);
-	void window_destroy(DisplayServer::WindowID p_window_id);
-	CD3DX12_CPU_DESCRIPTOR_HANDLE window_get_framebuffer_rtv_handle(DisplayServer::WindowID p_window = 0);
-	ID3D12Resource *window_get_framebuffer_texture(DisplayServer::WindowID p_window = 0);
-
-	RID local_device_create();
-	ComPtr<ID3D12Device> local_device_get_d3d12_device(RID p_local_device);
-	void local_device_push_command_lists(RID p_local_device, ID3D12CommandList *const *p_lists, int p_count);
-	void local_device_sync(RID p_local_device);
-	void local_device_free(RID p_local_device);
+	ID3D12Device *get_device();
+	IDXGIAdapter *get_adapter();
+	virtual int get_swapchain_image_count() const override final;
+
+	struct WindowPlatformData {
+		HWND window;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
+	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override final;
+	virtual int window_get_width(DisplayServer::WindowID p_window = 0) override final;
+	virtual int window_get_height(DisplayServer::WindowID p_window = 0) override final;
+	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) override final;
+	virtual void window_destroy(DisplayServer::WindowID p_window_id) override final;
+	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) override final;
+	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) override final;
+
+	virtual RID local_device_create() override final;
+	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) override final;
+	virtual void local_device_sync(RID p_local_device) override final;
+	virtual void local_device_free(RID p_local_device) override final;
 
 	DXGI_FORMAT get_screen_format() const;
-	DeviceLimits get_device_limits() const;
+	const DeviceLimits &get_device_limits() const;
 
-	void set_setup_list(ID3D12CommandList *p_command_list);
-	void append_command_list(ID3D12CommandList *p_command_list);
+	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
+	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
 	void resize_notify();
-	void flush(bool p_flush_setup = false, bool p_flush_pending = false);
-	void prepare_buffers(ID3D12GraphicsCommandList *p_command_list);
-	void postpare_buffers(ID3D12GraphicsCommandList *p_command_list);
-	Error swap_buffers();
-	Error initialize();
-
-	void command_begin_label(ID3D12GraphicsCommandList *p_command_list, String p_label_name, const Color p_color);
-	void command_insert_label(ID3D12GraphicsCommandList *p_command_list, String p_label_name, const Color p_color);
-	void command_end_label(ID3D12GraphicsCommandList *p_command_list);
+	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final;
+	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
+	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
+	virtual Error swap_buffers() override final;
+	virtual Error initialize() override final;
+
+	virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
+	virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
+	virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final;
 	void set_object_name(ID3D12Object *p_object, String p_object_name);
 
-	String get_device_vendor_name() const;
-	String get_device_name() const;
-	RenderingDevice::DeviceType get_device_type() const;
-	String get_device_api_version() const;
-	String get_device_pipeline_cache_uuid() const;
+	virtual String get_device_vendor_name() const override final;
+	virtual String get_device_name() const override final;
+	virtual RDD::DeviceType get_device_type() const override final;
+	virtual String get_device_api_version() const override final;
+	virtual String get_device_pipeline_cache_uuid() const override final;
+
+	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) override final;
+	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
 
-	void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
-	DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const;
+	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
 
 	D3D12Context();
 	virtual ~D3D12Context();

+ 17 - 0
drivers/d3d12/d3d12ma.cpp

@@ -30,5 +30,22 @@
 
 #include "d3d12_context.h"
 
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wduplicated-branches"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+#endif
+
+#if defined(_MSC_VER)
 #pragma warning(disable : 4189 4324 4505)
+#endif
+
 #include "thirdparty/d3d12ma/D3D12MemAlloc.cpp"

+ 0 - 9480
drivers/d3d12/rendering_device_d3d12.cpp

@@ -1,9480 +0,0 @@
-/**************************************************************************/
-/*  rendering_device_d3d12.cpp                                            */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "rendering_device_d3d12.h"
-
-#include "core/config/project_settings.h"
-#include "core/io/compression.h"
-#include "core/io/file_access.h"
-#include "core/io/marshalls.h"
-#include "core/object/worker_thread_pool.h"
-#include "core/os/os.h"
-#include "core/templates/hashfuncs.h"
-#include "d3d12_godot_nir_bridge.h"
-#include "modules/regex/regex.h"
-#include "thirdparty/zlib/zlib.h"
-
-#ifdef DEV_ENABLED
-#include "core/crypto/hashing_context.h"
-#endif
-
-// No point in fighting warnings in Mesa.
-#pragma warning(push)
-#pragma warning(disable : 4200) // "nonstandard extension used: zero-sized array in struct/union".
-#pragma warning(disable : 4806) // "'&': unsafe operation: no value of type 'bool' promoted to type 'uint32_t' can equal the given constant".
-#include "dxil_validator.h"
-#include "nir_spirv.h"
-#include "nir_to_dxil.h"
-#include "spirv_to_dxil.h"
-extern "C" {
-#include "dxil_spirv_nir.h"
-}
-#pragma warning(pop)
-
-#define ALIGN(m_number, m_alignment) ((((m_number) + ((m_alignment)-1)) / (m_alignment)) * (m_alignment))
-
-#ifdef USE_SMALL_ALLOCS_POOL
-static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
-#endif
-
-static const D3D12_RANGE VOID_RANGE = {};
-
-static const uint32_t MAX_VULKAN_SETS = 16;
-static const uint32_t ROOT_CONSTANT_SPACE = MAX_VULKAN_SETS + 1;
-static const uint32_t ROOT_CONSTANT_REGISTER = 0;
-static const uint32_t RUNTIME_DATA_SPACE = MAX_VULKAN_SETS + 2;
-static const uint32_t RUNTIME_DATA_REGISTER = 0;
-
-static const uint32_t MAX_IMAGE_FORMAT_PLANES = 2;
-
-#ifdef DEV_ENABLED
-//#define DEBUG_COUNT_BARRIERS
-#endif
-
-RenderingDeviceD3D12::Buffer *RenderingDeviceD3D12::_get_buffer_from_owner(RID p_buffer) {
-	Buffer *buffer = nullptr;
-	if (vertex_buffer_owner.owns(p_buffer)) {
-		buffer = vertex_buffer_owner.get_or_null(p_buffer);
-	} else if (index_buffer_owner.owns(p_buffer)) {
-		buffer = index_buffer_owner.get_or_null(p_buffer);
-	} else if (uniform_buffer_owner.owns(p_buffer)) {
-		buffer = uniform_buffer_owner.get_or_null(p_buffer);
-	} else if (texture_buffer_owner.owns(p_buffer)) {
-		buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer;
-	} else if (storage_buffer_owner.owns(p_buffer)) {
-		buffer = storage_buffer_owner.get_or_null(p_buffer);
-	}
-	return buffer;
-}
-
-void RenderingDeviceD3D12::_add_dependency(RID p_id, RID p_depends_on) {
-	if (!dependency_map.has(p_depends_on)) {
-		dependency_map[p_depends_on] = HashSet<RID>();
-	}
-
-	dependency_map[p_depends_on].insert(p_id);
-
-	if (!reverse_dependency_map.has(p_id)) {
-		reverse_dependency_map[p_id] = HashSet<RID>();
-	}
-
-	reverse_dependency_map[p_id].insert(p_depends_on);
-}
-
-void RenderingDeviceD3D12::_free_dependencies(RID p_id) {
-	// Direct dependencies must be freed.
-
-	HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);
-	if (E) {
-		while (E->value.size()) {
-			free(*E->value.begin());
-		}
-		dependency_map.remove(E);
-	}
-
-	// Reverse dependencies must be unreferenced.
-	E = reverse_dependency_map.find(p_id);
-
-	if (E) {
-		for (const RID &F : E->value) {
-			HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F);
-			ERR_CONTINUE(!G);
-			ERR_CONTINUE(!G->value.has(p_id));
-			G->value.erase(p_id);
-		}
-
-		reverse_dependency_map.remove(E);
-	}
-}
-
-// NOTE: RD's packed format names are reversed in relation to DXGI's; e.g.:.
-// - DATA_FORMAT_A8B8G8R8_UNORM_PACK32 -> DXGI_FORMAT_R8G8B8A8_UNORM (packed; note ABGR vs. RGBA).
-// - DATA_FORMAT_B8G8R8A8_UNORM -> DXGI_FORMAT_B8G8R8A8_UNORM (not packed; note BGRA order matches).
-// TODO: Add YUV formats properly, which would require better support for planes in the RD API.
-const RenderingDeviceD3D12::D3D12Format RenderingDeviceD3D12::d3d12_formats[RenderingDevice::DATA_FORMAT_MAX] = {
-	/* DATA_FORMAT_R4G4_UNORM_PACK8 */ {},
-	/* DATA_FORMAT_R4G4B4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
-	/* DATA_FORMAT_B4G4R4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
-	/* DATA_FORMAT_R5G6B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM },
-	/* DATA_FORMAT_B5G6R5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
-	/* DATA_FORMAT_R5G5B5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
-	/* DATA_FORMAT_B5G5R5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
-	/* DATA_FORMAT_A1R5G5B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM },
-	/* DATA_FORMAT_R8_UNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM },
-	/* DATA_FORMAT_R8_SNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SNORM },
-	/* DATA_FORMAT_R8_USCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
-	/* DATA_FORMAT_R8_SSCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
-	/* DATA_FORMAT_R8_UINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
-	/* DATA_FORMAT_R8_SINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
-	/* DATA_FORMAT_R8_SRGB */ {},
-	/* DATA_FORMAT_R8G8_UNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM },
-	/* DATA_FORMAT_R8G8_SNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SNORM },
-	/* DATA_FORMAT_R8G8_USCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
-	/* DATA_FORMAT_R8G8_SSCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
-	/* DATA_FORMAT_R8G8_UINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
-	/* DATA_FORMAT_R8G8_SINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
-	/* DATA_FORMAT_R8G8_SRGB */ {},
-	/* DATA_FORMAT_R8G8B8_UNORM */ {},
-	/* DATA_FORMAT_R8G8B8_SNORM */ {},
-	/* DATA_FORMAT_R8G8B8_USCALED */ {},
-	/* DATA_FORMAT_R8G8B8_SSCALED */ {},
-	/* DATA_FORMAT_R8G8B8_UINT */ {},
-	/* DATA_FORMAT_R8G8B8_SINT */ {},
-	/* DATA_FORMAT_R8G8B8_SRGB */ {},
-	/* DATA_FORMAT_B8G8R8_UNORM */ {},
-	/* DATA_FORMAT_B8G8R8_SNORM */ {},
-	/* DATA_FORMAT_B8G8R8_USCALED */ {},
-	/* DATA_FORMAT_B8G8R8_SSCALED */ {},
-	/* DATA_FORMAT_B8G8R8_UINT */ {},
-	/* DATA_FORMAT_B8G8R8_SINT */ {},
-	/* DATA_FORMAT_B8G8R8_SRGB */ {},
-	/* DATA_FORMAT_R8G8B8A8_UNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
-	/* DATA_FORMAT_R8G8B8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
-	/* DATA_FORMAT_R8G8B8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_R8G8B8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_R8G8B8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_R8G8B8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_R8G8B8A8_SRGB */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
-	/* DATA_FORMAT_B8G8R8A8_UNORM */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM },
-	/* DATA_FORMAT_B8G8R8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
-	/* DATA_FORMAT_B8G8R8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_B8G8R8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_B8G8R8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_B8G8R8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_B8G8R8A8_SRGB */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
-	/* DATA_FORMAT_A8B8G8R8_UNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
-	/* DATA_FORMAT_A8B8G8R8_SNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
-	/* DATA_FORMAT_A8B8G8R8_USCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_A8B8G8R8_SSCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_A8B8G8R8_UINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
-	/* DATA_FORMAT_A8B8G8R8_SINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
-	/* DATA_FORMAT_A8B8G8R8_SRGB_PACK32 */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },
-	/* DATA_FORMAT_A2R10G10B10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
-	/* DATA_FORMAT_A2R10G10B10_SNORM_PACK32 */ {},
-	/* DATA_FORMAT_A2R10G10B10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
-	/* DATA_FORMAT_A2R10G10B10_SSCALED_PACK32 */ {},
-	/* DATA_FORMAT_A2R10G10B10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
-	/* DATA_FORMAT_A2R10G10B10_SINT_PACK32 */ {},
-	/* DATA_FORMAT_A2B10G10R10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM },
-	/* DATA_FORMAT_A2B10G10R10_SNORM_PACK32 */ {},
-	/* DATA_FORMAT_A2B10G10R10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
-	/* DATA_FORMAT_A2B10G10R10_SSCALED_PACK32 */ {},
-	/* DATA_FORMAT_A2B10G10R10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
-	/* DATA_FORMAT_A2B10G10R10_SINT_PACK32 */ {},
-	/* DATA_FORMAT_R16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM },
-	/* DATA_FORMAT_R16_SNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SNORM },
-	/* DATA_FORMAT_R16_USCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
-	/* DATA_FORMAT_R16_SSCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
-	/* DATA_FORMAT_R16_UINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
-	/* DATA_FORMAT_R16_SINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
-	/* DATA_FORMAT_R16_SFLOAT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_FLOAT },
-	/* DATA_FORMAT_R16G16_UNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM },
-	/* DATA_FORMAT_R16G16_SNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SNORM },
-	/* DATA_FORMAT_R16G16_USCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
-	/* DATA_FORMAT_R16G16_SSCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
-	/* DATA_FORMAT_R16G16_UINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
-	/* DATA_FORMAT_R16G16_SINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
-	/* DATA_FORMAT_R16G16_SFLOAT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_FLOAT },
-	/* DATA_FORMAT_R16G16B16_UNORM */ {},
-	/* DATA_FORMAT_R16G16B16_SNORM */ {},
-	/* DATA_FORMAT_R16G16B16_USCALED */ {},
-	/* DATA_FORMAT_R16G16B16_SSCALED */ {},
-	/* DATA_FORMAT_R16G16B16_UINT */ {},
-	/* DATA_FORMAT_R16G16B16_SINT */ {},
-	/* DATA_FORMAT_R16G16B16_SFLOAT */ {},
-	/* DATA_FORMAT_R16G16B16A16_UNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM },
-	/* DATA_FORMAT_R16G16B16A16_SNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SNORM },
-	/* DATA_FORMAT_R16G16B16A16_USCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
-	/* DATA_FORMAT_R16G16B16A16_SSCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
-	/* DATA_FORMAT_R16G16B16A16_UINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
-	/* DATA_FORMAT_R16G16B16A16_SINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
-	/* DATA_FORMAT_R16G16B16A16_SFLOAT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_FLOAT },
-	/* DATA_FORMAT_R32_UINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT },
-	/* DATA_FORMAT_R32_SINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_SINT },
-	/* DATA_FORMAT_R32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT },
-	/* DATA_FORMAT_R32G32_UINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_UINT },
-	/* DATA_FORMAT_R32G32_SINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_SINT },
-	/* DATA_FORMAT_R32G32_SFLOAT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_FLOAT },
-	/* DATA_FORMAT_R32G32B32_UINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_UINT },
-	/* DATA_FORMAT_R32G32B32_SINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_SINT },
-	/* DATA_FORMAT_R32G32B32_SFLOAT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT },
-	/* DATA_FORMAT_R32G32B32A32_UINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_UINT },
-	/* DATA_FORMAT_R32G32B32A32_SINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_SINT },
-	/* DATA_FORMAT_R32G32B32A32_SFLOAT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT },
-	/* DATA_FORMAT_R64_UINT */ {},
-	/* DATA_FORMAT_R64_SINT */ {},
-	/* DATA_FORMAT_R64_SFLOAT */ {},
-	/* DATA_FORMAT_R64G64_UINT */ {},
-	/* DATA_FORMAT_R64G64_SINT */ {},
-	/* DATA_FORMAT_R64G64_SFLOAT */ {},
-	/* DATA_FORMAT_R64G64B64_UINT */ {},
-	/* DATA_FORMAT_R64G64B64_SINT */ {},
-	/* DATA_FORMAT_R64G64B64_SFLOAT */ {},
-	/* DATA_FORMAT_R64G64B64A64_UINT */ {},
-	/* DATA_FORMAT_R64G64B64A64_SINT */ {},
-	/* DATA_FORMAT_R64G64B64A64_SFLOAT */ {},
-	/* DATA_FORMAT_B10G11R11_UFLOAT_PACK32 */ { DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT },
-	/* DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32 */ { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
-	/* DATA_FORMAT_D16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, 0, DXGI_FORMAT_D16_UNORM },
-	/* DATA_FORMAT_X8_D24_UNORM_PACK32 */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
-	/* DATA_FORMAT_D32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT },
-	/* DATA_FORMAT_S8_UINT */ {},
-	/* DATA_FORMAT_D16_UNORM_S8_UINT */ {},
-	/* DATA_FORMAT_D24_UNORM_S8_UINT */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
-	/* DATA_FORMAT_D32_SFLOAT_S8_UINT */ { DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT_S8X24_UINT },
-	/* DATA_FORMAT_BC1_RGB_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
-	/* DATA_FORMAT_BC1_RGB_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
-	/* DATA_FORMAT_BC1_RGBA_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM },
-	/* DATA_FORMAT_BC1_RGBA_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB },
-	/* DATA_FORMAT_BC2_UNORM_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM },
-	/* DATA_FORMAT_BC2_SRGB_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM_SRGB },
-	/* DATA_FORMAT_BC3_UNORM_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM },
-	/* DATA_FORMAT_BC3_SRGB_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM_SRGB },
-	/* DATA_FORMAT_BC4_UNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM },
-	/* DATA_FORMAT_BC4_SNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_SNORM },
-	/* DATA_FORMAT_BC5_UNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM },
-	/* DATA_FORMAT_BC5_SNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_SNORM },
-	/* DATA_FORMAT_BC6H_UFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16 },
-	/* DATA_FORMAT_BC6H_SFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_SF16 },
-	/* DATA_FORMAT_BC7_UNORM_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM },
-	/* DATA_FORMAT_BC7_SRGB_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM_SRGB },
-	/* DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_EAC_R11_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_EAC_R11_SNORM_BLOCK */ {},
-	/* DATA_FORMAT_EAC_R11G11_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_EAC_R11G11_SNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_4x4_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_4x4_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_5x4_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_5x4_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_5x5_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_5x5_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_6x5_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_6x5_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_6x6_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_6x6_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x5_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x5_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x6_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x6_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x8_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_8x8_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x5_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x5_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x6_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x6_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x8_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x8_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x10_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_10x10_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_12x10_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_12x10_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_12x12_UNORM_BLOCK */ {},
-	/* DATA_FORMAT_ASTC_12x12_SRGB_BLOCK */ {},
-	/* DATA_FORMAT_G8B8G8R8_422_UNORM */ {},
-	/* DATA_FORMAT_B8G8R8G8_422_UNORM */ {},
-	/* DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM */ {},
-	/* DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM */ {},
-	/* DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM */ {},
-	/* DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM */ {},
-	/* DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM */ {},
-	/* DATA_FORMAT_R10X6_UNORM_PACK16 */ {},
-	/* DATA_FORMAT_R10X6G10X6_UNORM_2PACK16 */ {},
-	/* DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_R12X4_UNORM_PACK16 */ {},
-	/* DATA_FORMAT_R12X4G12X4_UNORM_2PACK16 */ {},
-	/* DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 */ {},
-	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 */ {},
-	/* DATA_FORMAT_G16B16G16R16_422_UNORM */ {},
-	/* DATA_FORMAT_B16G16R16G16_422_UNORM */ {},
-	/* DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM */ {},
-	/* DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM */ {},
-	/* DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM */ {},
-	/* DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM */ {},
-	/* DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM */ {},
-};
-
-const char *RenderingDeviceD3D12::named_formats[RenderingDevice::DATA_FORMAT_MAX] = {
-	"R4G4_Unorm_Pack8",
-	"R4G4B4A4_Unorm_Pack16",
-	"B4G4R4A4_Unorm_Pack16",
-	"R5G6B5_Unorm_Pack16",
-	"B5G6R5_Unorm_Pack16",
-	"R5G5B5A1_Unorm_Pack16",
-	"B5G5R5A1_Unorm_Pack16",
-	"A1R5G5B5_Unorm_Pack16",
-	"R8_Unorm",
-	"R8_Snorm",
-	"R8_Uscaled",
-	"R8_Sscaled",
-	"R8_Uint",
-	"R8_Sint",
-	"R8_Srgb",
-	"R8G8_Unorm",
-	"R8G8_Snorm",
-	"R8G8_Uscaled",
-	"R8G8_Sscaled",
-	"R8G8_Uint",
-	"R8G8_Sint",
-	"R8G8_Srgb",
-	"R8G8B8_Unorm",
-	"R8G8B8_Snorm",
-	"R8G8B8_Uscaled",
-	"R8G8B8_Sscaled",
-	"R8G8B8_Uint",
-	"R8G8B8_Sint",
-	"R8G8B8_Srgb",
-	"B8G8R8_Unorm",
-	"B8G8R8_Snorm",
-	"B8G8R8_Uscaled",
-	"B8G8R8_Sscaled",
-	"B8G8R8_Uint",
-	"B8G8R8_Sint",
-	"B8G8R8_Srgb",
-	"R8G8B8A8_Unorm",
-	"R8G8B8A8_Snorm",
-	"R8G8B8A8_Uscaled",
-	"R8G8B8A8_Sscaled",
-	"R8G8B8A8_Uint",
-	"R8G8B8A8_Sint",
-	"R8G8B8A8_Srgb",
-	"B8G8R8A8_Unorm",
-	"B8G8R8A8_Snorm",
-	"B8G8R8A8_Uscaled",
-	"B8G8R8A8_Sscaled",
-	"B8G8R8A8_Uint",
-	"B8G8R8A8_Sint",
-	"B8G8R8A8_Srgb",
-	"A8B8G8R8_Unorm_Pack32",
-	"A8B8G8R8_Snorm_Pack32",
-	"A8B8G8R8_Uscaled_Pack32",
-	"A8B8G8R8_Sscaled_Pack32",
-	"A8B8G8R8_Uint_Pack32",
-	"A8B8G8R8_Sint_Pack32",
-	"A8B8G8R8_Srgb_Pack32",
-	"A2R10G10B10_Unorm_Pack32",
-	"A2R10G10B10_Snorm_Pack32",
-	"A2R10G10B10_Uscaled_Pack32",
-	"A2R10G10B10_Sscaled_Pack32",
-	"A2R10G10B10_Uint_Pack32",
-	"A2R10G10B10_Sint_Pack32",
-	"A2B10G10R10_Unorm_Pack32",
-	"A2B10G10R10_Snorm_Pack32",
-	"A2B10G10R10_Uscaled_Pack32",
-	"A2B10G10R10_Sscaled_Pack32",
-	"A2B10G10R10_Uint_Pack32",
-	"A2B10G10R10_Sint_Pack32",
-	"R16_Unorm",
-	"R16_Snorm",
-	"R16_Uscaled",
-	"R16_Sscaled",
-	"R16_Uint",
-	"R16_Sint",
-	"R16_Sfloat",
-	"R16G16_Unorm",
-	"R16G16_Snorm",
-	"R16G16_Uscaled",
-	"R16G16_Sscaled",
-	"R16G16_Uint",
-	"R16G16_Sint",
-	"R16G16_Sfloat",
-	"R16G16B16_Unorm",
-	"R16G16B16_Snorm",
-	"R16G16B16_Uscaled",
-	"R16G16B16_Sscaled",
-	"R16G16B16_Uint",
-	"R16G16B16_Sint",
-	"R16G16B16_Sfloat",
-	"R16G16B16A16_Unorm",
-	"R16G16B16A16_Snorm",
-	"R16G16B16A16_Uscaled",
-	"R16G16B16A16_Sscaled",
-	"R16G16B16A16_Uint",
-	"R16G16B16A16_Sint",
-	"R16G16B16A16_Sfloat",
-	"R32_Uint",
-	"R32_Sint",
-	"R32_Sfloat",
-	"R32G32_Uint",
-	"R32G32_Sint",
-	"R32G32_Sfloat",
-	"R32G32B32_Uint",
-	"R32G32B32_Sint",
-	"R32G32B32_Sfloat",
-	"R32G32B32A32_Uint",
-	"R32G32B32A32_Sint",
-	"R32G32B32A32_Sfloat",
-	"R64_Uint",
-	"R64_Sint",
-	"R64_Sfloat",
-	"R64G64_Uint",
-	"R64G64_Sint",
-	"R64G64_Sfloat",
-	"R64G64B64_Uint",
-	"R64G64B64_Sint",
-	"R64G64B64_Sfloat",
-	"R64G64B64A64_Uint",
-	"R64G64B64A64_Sint",
-	"R64G64B64A64_Sfloat",
-	"B10G11R11_Ufloat_Pack32",
-	"E5B9G9R9_Ufloat_Pack32",
-	"D16_Unorm",
-	"X8_D24_Unorm_Pack32",
-	"D32_Sfloat",
-	"S8_Uint",
-	"D16_Unorm_S8_Uint",
-	"D24_Unorm_S8_Uint",
-	"D32_Sfloat_S8_Uint",
-	"Bc1_Rgb_Unorm_Block",
-	"Bc1_Rgb_Srgb_Block",
-	"Bc1_Rgba_Unorm_Block",
-	"Bc1_Rgba_Srgb_Block",
-	"Bc2_Unorm_Block",
-	"Bc2_Srgb_Block",
-	"Bc3_Unorm_Block",
-	"Bc3_Srgb_Block",
-	"Bc4_Unorm_Block",
-	"Bc4_Snorm_Block",
-	"Bc5_Unorm_Block",
-	"Bc5_Snorm_Block",
-	"Bc6H_Ufloat_Block",
-	"Bc6H_Sfloat_Block",
-	"Bc7_Unorm_Block",
-	"Bc7_Srgb_Block",
-	"Etc2_R8G8B8_Unorm_Block",
-	"Etc2_R8G8B8_Srgb_Block",
-	"Etc2_R8G8B8A1_Unorm_Block",
-	"Etc2_R8G8B8A1_Srgb_Block",
-	"Etc2_R8G8B8A8_Unorm_Block",
-	"Etc2_R8G8B8A8_Srgb_Block",
-	"Eac_R11_Unorm_Block",
-	"Eac_R11_Snorm_Block",
-	"Eac_R11G11_Unorm_Block",
-	"Eac_R11G11_Snorm_Block",
-	"Astc_4X4_Unorm_Block",
-	"Astc_4X4_Srgb_Block",
-	"Astc_5X4_Unorm_Block",
-	"Astc_5X4_Srgb_Block",
-	"Astc_5X5_Unorm_Block",
-	"Astc_5X5_Srgb_Block",
-	"Astc_6X5_Unorm_Block",
-	"Astc_6X5_Srgb_Block",
-	"Astc_6X6_Unorm_Block",
-	"Astc_6X6_Srgb_Block",
-	"Astc_8X5_Unorm_Block",
-	"Astc_8X5_Srgb_Block",
-	"Astc_8X6_Unorm_Block",
-	"Astc_8X6_Srgb_Block",
-	"Astc_8X8_Unorm_Block",
-	"Astc_8X8_Srgb_Block",
-	"Astc_10X5_Unorm_Block",
-	"Astc_10X5_Srgb_Block",
-	"Astc_10X6_Unorm_Block",
-	"Astc_10X6_Srgb_Block",
-	"Astc_10X8_Unorm_Block",
-	"Astc_10X8_Srgb_Block",
-	"Astc_10X10_Unorm_Block",
-	"Astc_10X10_Srgb_Block",
-	"Astc_12X10_Unorm_Block",
-	"Astc_12X10_Srgb_Block",
-	"Astc_12X12_Unorm_Block",
-	"Astc_12X12_Srgb_Block",
-	"G8B8G8R8_422_Unorm",
-	"B8G8R8G8_422_Unorm",
-	"G8_B8_R8_3Plane_420_Unorm",
-	"G8_B8R8_2Plane_420_Unorm",
-	"G8_B8_R8_3Plane_422_Unorm",
-	"G8_B8R8_2Plane_422_Unorm",
-	"G8_B8_R8_3Plane_444_Unorm",
-	"R10X6_Unorm_Pack16",
-	"R10X6G10X6_Unorm_2Pack16",
-	"R10X6G10X6B10X6A10X6_Unorm_4Pack16",
-	"G10X6B10X6G10X6R10X6_422_Unorm_4Pack16",
-	"B10X6G10X6R10X6G10X6_422_Unorm_4Pack16",
-	"G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16",
-	"G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16",
-	"G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16",
-	"G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16",
-	"G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16",
-	"R12X4_Unorm_Pack16",
-	"R12X4G12X4_Unorm_2Pack16",
-	"R12X4G12X4B12X4A12X4_Unorm_4Pack16",
-	"G12X4B12X4G12X4R12X4_422_Unorm_4Pack16",
-	"B12X4G12X4R12X4G12X4_422_Unorm_4Pack16",
-	"G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16",
-	"G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16",
-	"G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16",
-	"G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16",
-	"G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16",
-	"G16B16G16R16_422_Unorm",
-	"B16G16R16G16_422_Unorm",
-	"G16_B16_R16_3Plane_420_Unorm",
-	"G16_B16R16_2Plane_420_Unorm",
-	"G16_B16_R16_3Plane_422_Unorm",
-	"G16_B16R16_2Plane_422_Unorm",
-	"G16_B16_R16_3Plane_444_Unorm",
-};
-
-int RenderingDeviceD3D12::get_format_vertex_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_R8_UNORM:
-		case DATA_FORMAT_R8_SNORM:
-		case DATA_FORMAT_R8_UINT:
-		case DATA_FORMAT_R8_SINT:
-		case DATA_FORMAT_R8G8_UNORM:
-		case DATA_FORMAT_R8G8_SNORM:
-		case DATA_FORMAT_R8G8_UINT:
-		case DATA_FORMAT_R8G8_SINT:
-		case DATA_FORMAT_R8G8B8_UNORM:
-		case DATA_FORMAT_R8G8B8_SNORM:
-		case DATA_FORMAT_R8G8B8_UINT:
-		case DATA_FORMAT_R8G8B8_SINT:
-		case DATA_FORMAT_B8G8R8_UNORM:
-		case DATA_FORMAT_B8G8R8_SNORM:
-		case DATA_FORMAT_B8G8R8_UINT:
-		case DATA_FORMAT_B8G8R8_SINT:
-		case DATA_FORMAT_R8G8B8A8_UNORM:
-		case DATA_FORMAT_R8G8B8A8_SNORM:
-		case DATA_FORMAT_R8G8B8A8_UINT:
-		case DATA_FORMAT_R8G8B8A8_SINT:
-		case DATA_FORMAT_B8G8R8A8_UNORM:
-		case DATA_FORMAT_B8G8R8A8_SNORM:
-		case DATA_FORMAT_B8G8R8A8_UINT:
-		case DATA_FORMAT_B8G8R8A8_SINT:
-		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
-			return 4;
-		case DATA_FORMAT_R16_UNORM:
-		case DATA_FORMAT_R16_SNORM:
-		case DATA_FORMAT_R16_UINT:
-		case DATA_FORMAT_R16_SINT:
-		case DATA_FORMAT_R16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16_UNORM:
-		case DATA_FORMAT_R16G16_SNORM:
-		case DATA_FORMAT_R16G16_UINT:
-		case DATA_FORMAT_R16G16_SINT:
-		case DATA_FORMAT_R16G16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16B16_UNORM:
-		case DATA_FORMAT_R16G16B16_SNORM:
-		case DATA_FORMAT_R16G16B16_UINT:
-		case DATA_FORMAT_R16G16B16_SINT:
-		case DATA_FORMAT_R16G16B16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R16G16B16A16_UNORM:
-		case DATA_FORMAT_R16G16B16A16_SNORM:
-		case DATA_FORMAT_R16G16B16A16_UINT:
-		case DATA_FORMAT_R16G16B16A16_SINT:
-		case DATA_FORMAT_R16G16B16A16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32_UINT:
-		case DATA_FORMAT_R32_SINT:
-		case DATA_FORMAT_R32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R32G32_UINT:
-		case DATA_FORMAT_R32G32_SINT:
-		case DATA_FORMAT_R32G32_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32G32B32_UINT:
-		case DATA_FORMAT_R32G32B32_SINT:
-		case DATA_FORMAT_R32G32B32_SFLOAT:
-			return 12;
-		case DATA_FORMAT_R32G32B32A32_UINT:
-		case DATA_FORMAT_R32G32B32A32_SINT:
-		case DATA_FORMAT_R32G32B32A32_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64_UINT:
-		case DATA_FORMAT_R64_SINT:
-		case DATA_FORMAT_R64_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R64G64_UINT:
-		case DATA_FORMAT_R64G64_SINT:
-		case DATA_FORMAT_R64G64_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64G64B64_UINT:
-		case DATA_FORMAT_R64G64B64_SINT:
-		case DATA_FORMAT_R64G64B64_SFLOAT:
-			return 24;
-		case DATA_FORMAT_R64G64B64A64_UINT:
-		case DATA_FORMAT_R64G64B64A64_SINT:
-		case DATA_FORMAT_R64G64B64A64_SFLOAT:
-			return 32;
-		default:
-			return 0;
-	}
-}
-
-uint32_t RenderingDeviceD3D12::get_image_format_pixel_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_R4G4_UNORM_PACK8:
-			return 1;
-		case DATA_FORMAT_R4G4B4A4_UNORM_PACK16:
-		case DATA_FORMAT_B4G4R4A4_UNORM_PACK16:
-		case DATA_FORMAT_R5G6B5_UNORM_PACK16:
-		case DATA_FORMAT_B5G6R5_UNORM_PACK16:
-		case DATA_FORMAT_R5G5B5A1_UNORM_PACK16:
-		case DATA_FORMAT_B5G5R5A1_UNORM_PACK16:
-		case DATA_FORMAT_A1R5G5B5_UNORM_PACK16:
-			return 2;
-		case DATA_FORMAT_R8_UNORM:
-		case DATA_FORMAT_R8_SNORM:
-		case DATA_FORMAT_R8_USCALED:
-		case DATA_FORMAT_R8_SSCALED:
-		case DATA_FORMAT_R8_UINT:
-		case DATA_FORMAT_R8_SINT:
-		case DATA_FORMAT_R8_SRGB:
-			return 1;
-		case DATA_FORMAT_R8G8_UNORM:
-		case DATA_FORMAT_R8G8_SNORM:
-		case DATA_FORMAT_R8G8_USCALED:
-		case DATA_FORMAT_R8G8_SSCALED:
-		case DATA_FORMAT_R8G8_UINT:
-		case DATA_FORMAT_R8G8_SINT:
-		case DATA_FORMAT_R8G8_SRGB:
-			return 2;
-		case DATA_FORMAT_R8G8B8_UNORM:
-		case DATA_FORMAT_R8G8B8_SNORM:
-		case DATA_FORMAT_R8G8B8_USCALED:
-		case DATA_FORMAT_R8G8B8_SSCALED:
-		case DATA_FORMAT_R8G8B8_UINT:
-		case DATA_FORMAT_R8G8B8_SINT:
-		case DATA_FORMAT_R8G8B8_SRGB:
-		case DATA_FORMAT_B8G8R8_UNORM:
-		case DATA_FORMAT_B8G8R8_SNORM:
-		case DATA_FORMAT_B8G8R8_USCALED:
-		case DATA_FORMAT_B8G8R8_SSCALED:
-		case DATA_FORMAT_B8G8R8_UINT:
-		case DATA_FORMAT_B8G8R8_SINT:
-		case DATA_FORMAT_B8G8R8_SRGB:
-			return 3;
-		case DATA_FORMAT_R8G8B8A8_UNORM:
-		case DATA_FORMAT_R8G8B8A8_SNORM:
-		case DATA_FORMAT_R8G8B8A8_USCALED:
-		case DATA_FORMAT_R8G8B8A8_SSCALED:
-		case DATA_FORMAT_R8G8B8A8_UINT:
-		case DATA_FORMAT_R8G8B8A8_SINT:
-		case DATA_FORMAT_R8G8B8A8_SRGB:
-		case DATA_FORMAT_B8G8R8A8_UNORM:
-		case DATA_FORMAT_B8G8R8A8_SNORM:
-		case DATA_FORMAT_B8G8R8A8_USCALED:
-		case DATA_FORMAT_B8G8R8A8_SSCALED:
-		case DATA_FORMAT_B8G8R8A8_UINT:
-		case DATA_FORMAT_B8G8R8A8_SINT:
-		case DATA_FORMAT_B8G8R8A8_SRGB:
-			return 4;
-		case DATA_FORMAT_A8B8G8R8_UNORM_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SNORM_PACK32:
-		case DATA_FORMAT_A8B8G8R8_USCALED_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32:
-		case DATA_FORMAT_A8B8G8R8_UINT_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SINT_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SRGB_PACK32:
-		case DATA_FORMAT_A2R10G10B10_UNORM_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SNORM_PACK32:
-		case DATA_FORMAT_A2R10G10B10_USCALED_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32:
-		case DATA_FORMAT_A2R10G10B10_UINT_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SINT_PACK32:
-		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SNORM_PACK32:
-		case DATA_FORMAT_A2B10G10R10_USCALED_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32:
-		case DATA_FORMAT_A2B10G10R10_UINT_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SINT_PACK32:
-			return 4;
-		case DATA_FORMAT_R16_UNORM:
-		case DATA_FORMAT_R16_SNORM:
-		case DATA_FORMAT_R16_USCALED:
-		case DATA_FORMAT_R16_SSCALED:
-		case DATA_FORMAT_R16_UINT:
-		case DATA_FORMAT_R16_SINT:
-		case DATA_FORMAT_R16_SFLOAT:
-			return 2;
-		case DATA_FORMAT_R16G16_UNORM:
-		case DATA_FORMAT_R16G16_SNORM:
-		case DATA_FORMAT_R16G16_USCALED:
-		case DATA_FORMAT_R16G16_SSCALED:
-		case DATA_FORMAT_R16G16_UINT:
-		case DATA_FORMAT_R16G16_SINT:
-		case DATA_FORMAT_R16G16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16B16_UNORM:
-		case DATA_FORMAT_R16G16B16_SNORM:
-		case DATA_FORMAT_R16G16B16_USCALED:
-		case DATA_FORMAT_R16G16B16_SSCALED:
-		case DATA_FORMAT_R16G16B16_UINT:
-		case DATA_FORMAT_R16G16B16_SINT:
-		case DATA_FORMAT_R16G16B16_SFLOAT:
-			return 6;
-		case DATA_FORMAT_R16G16B16A16_UNORM:
-		case DATA_FORMAT_R16G16B16A16_SNORM:
-		case DATA_FORMAT_R16G16B16A16_USCALED:
-		case DATA_FORMAT_R16G16B16A16_SSCALED:
-		case DATA_FORMAT_R16G16B16A16_UINT:
-		case DATA_FORMAT_R16G16B16A16_SINT:
-		case DATA_FORMAT_R16G16B16A16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32_UINT:
-		case DATA_FORMAT_R32_SINT:
-		case DATA_FORMAT_R32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R32G32_UINT:
-		case DATA_FORMAT_R32G32_SINT:
-		case DATA_FORMAT_R32G32_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32G32B32_UINT:
-		case DATA_FORMAT_R32G32B32_SINT:
-		case DATA_FORMAT_R32G32B32_SFLOAT:
-			return 12;
-		case DATA_FORMAT_R32G32B32A32_UINT:
-		case DATA_FORMAT_R32G32B32A32_SINT:
-		case DATA_FORMAT_R32G32B32A32_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64_UINT:
-		case DATA_FORMAT_R64_SINT:
-		case DATA_FORMAT_R64_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R64G64_UINT:
-		case DATA_FORMAT_R64G64_SINT:
-		case DATA_FORMAT_R64G64_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64G64B64_UINT:
-		case DATA_FORMAT_R64G64B64_SINT:
-		case DATA_FORMAT_R64G64B64_SFLOAT:
-			return 24;
-		case DATA_FORMAT_R64G64B64A64_UINT:
-		case DATA_FORMAT_R64G64B64A64_SINT:
-		case DATA_FORMAT_R64G64B64A64_SFLOAT:
-			return 32;
-		case DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
-		case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32:
-			return 4;
-		case DATA_FORMAT_D16_UNORM:
-			return 2;
-		case DATA_FORMAT_X8_D24_UNORM_PACK32:
-			return 4;
-		case DATA_FORMAT_D32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_S8_UINT:
-			return 1;
-		case DATA_FORMAT_D16_UNORM_S8_UINT:
-			return 4;
-		case DATA_FORMAT_D24_UNORM_S8_UINT:
-			return 4;
-		case DATA_FORMAT_D32_SFLOAT_S8_UINT:
-			return 5; // ?
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-			return 1;
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_G8B8G8R8_422_UNORM:
-		case DATA_FORMAT_B8G8R8G8_422_UNORM:
-			return 4;
-		case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
-		case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM:
-		case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
-		case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM:
-		case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
-			return 4;
-		case DATA_FORMAT_R10X6_UNORM_PACK16:
-		case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16:
-		case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
-		case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
-		case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
-		case DATA_FORMAT_R12X4_UNORM_PACK16:
-		case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16:
-		case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
-		case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
-		case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
-			return 2;
-		case DATA_FORMAT_G16B16G16R16_422_UNORM:
-		case DATA_FORMAT_B16G16R16G16_422_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
-		case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
-		case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
-			return 8;
-		default: {
-			ERR_PRINT("Format not handled, bug");
-		}
-	}
-
-	return 1;
-}
-
-// https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf
-
-void RenderingDeviceD3D12::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			r_w = 4;
-			r_h = 4;
-			return;
-		default: {
-			r_w = 1;
-			r_h = 1;
-		}
-	}
-}
-
-uint32_t RenderingDeviceD3D12::get_compressed_image_format_block_byte_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-			return 8;
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-			return 8;
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-			return 16;
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			return 8; // Wrong.
-		default: {
-		}
-	}
-	return 1;
-}
-
-uint32_t RenderingDeviceD3D12::get_compressed_image_format_pixel_rshift(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1.
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-			return 1;
-		default: {
-		}
-	}
-
-	return 0;
-}
-
-uint32_t RenderingDeviceD3D12::get_image_format_plane_count(DataFormat p_format) {
-	uint32_t planes = 1;
-	switch (p_format) {
-		case DATA_FORMAT_D16_UNORM_S8_UINT:
-		case DATA_FORMAT_D24_UNORM_S8_UINT:
-		case DATA_FORMAT_D32_SFLOAT_S8_UINT: {
-			planes = 2;
-		}
-		default: {
-		}
-	}
-	DEV_ASSERT(planes <= MAX_IMAGE_FORMAT_PLANES);
-	return planes;
-}
-
-uint32_t RenderingDeviceD3D12::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) {
-	ERR_FAIL_COND_V(p_mipmaps == 0, 0);
-	uint32_t w = p_width;
-	uint32_t h = p_height;
-	uint32_t d = p_depth;
-
-	uint32_t size = 0;
-
-	uint32_t pixel_size = get_image_format_pixel_size(p_format);
-	uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format);
-	uint32_t blockw, blockh;
-	get_compressed_image_format_block_dimensions(p_format, blockw, blockh);
-
-	for (uint32_t i = 0; i < p_mipmaps; i++) {
-		uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w;
-		uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h;
-
-		uint32_t s = bw * bh;
-
-		s *= pixel_size;
-		s >>= pixel_rshift;
-		size += s * d;
-		if (r_blockw) {
-			*r_blockw = bw;
-		}
-		if (r_blockh) {
-			*r_blockh = bh;
-		}
-		if (r_depth) {
-			*r_depth = d;
-		}
-		w = MAX(blockw, w >> 1);
-		h = MAX(blockh, h >> 1);
-		d = MAX(1u, d >> 1);
-	}
-
-	return size;
-}
-
-uint32_t RenderingDeviceD3D12::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
-	// Formats and block size don't really matter here since they can all go down to 1px (even if block is larger).
-	uint32_t w = p_width;
-	uint32_t h = p_height;
-	uint32_t d = p_depth;
-
-	uint32_t mipmaps = 1;
-
-	while (true) {
-		if (w == 1 && h == 1 && d == 1) {
-			break;
-		}
-
-		w = MAX(1u, w >> 1);
-		h = MAX(1u, h >> 1);
-		d = MAX(1u, d >> 1);
-
-		mipmaps++;
-	}
-
-	return mipmaps;
-}
-
-///////////////////////
-
-const D3D12_COMPARISON_FUNC RenderingDeviceD3D12::compare_operators[RenderingDevice::COMPARE_OP_MAX] = {
-	D3D12_COMPARISON_FUNC_NEVER,
-	D3D12_COMPARISON_FUNC_LESS,
-	D3D12_COMPARISON_FUNC_EQUAL,
-	D3D12_COMPARISON_FUNC_LESS_EQUAL,
-	D3D12_COMPARISON_FUNC_GREATER,
-	D3D12_COMPARISON_FUNC_NOT_EQUAL,
-	D3D12_COMPARISON_FUNC_GREATER_EQUAL,
-	D3D12_COMPARISON_FUNC_ALWAYS,
-};
-
-const D3D12_STENCIL_OP RenderingDeviceD3D12::stencil_operations[RenderingDevice::STENCIL_OP_MAX] = {
-	D3D12_STENCIL_OP_KEEP,
-	D3D12_STENCIL_OP_ZERO,
-	D3D12_STENCIL_OP_REPLACE,
-	D3D12_STENCIL_OP_INCR_SAT,
-	D3D12_STENCIL_OP_DECR_SAT,
-	D3D12_STENCIL_OP_INVERT,
-	D3D12_STENCIL_OP_INCR,
-	D3D12_STENCIL_OP_DECR,
-};
-
-const UINT RenderingDeviceD3D12::rasterization_sample_count[RenderingDevice::TEXTURE_SAMPLES_MAX] = {
-	1,
-	2,
-	4,
-	8,
-	16,
-	32,
-	64,
-};
-
-const D3D12_LOGIC_OP RenderingDeviceD3D12::logic_operations[RenderingDevice::LOGIC_OP_MAX] = {
-	D3D12_LOGIC_OP_CLEAR,
-	D3D12_LOGIC_OP_AND,
-	D3D12_LOGIC_OP_AND_REVERSE,
-	D3D12_LOGIC_OP_COPY,
-	D3D12_LOGIC_OP_AND_INVERTED,
-	D3D12_LOGIC_OP_NOOP,
-	D3D12_LOGIC_OP_XOR,
-	D3D12_LOGIC_OP_OR,
-	D3D12_LOGIC_OP_NOR,
-	D3D12_LOGIC_OP_EQUIV,
-	D3D12_LOGIC_OP_INVERT,
-	D3D12_LOGIC_OP_OR_REVERSE,
-	D3D12_LOGIC_OP_COPY_INVERTED,
-	D3D12_LOGIC_OP_OR_INVERTED,
-	D3D12_LOGIC_OP_NAND,
-	D3D12_LOGIC_OP_SET,
-};
-
-const D3D12_BLEND RenderingDeviceD3D12::blend_factors[RenderingDevice::BLEND_FACTOR_MAX] = {
-	D3D12_BLEND_ZERO,
-	D3D12_BLEND_ONE,
-	D3D12_BLEND_SRC_COLOR,
-	D3D12_BLEND_INV_SRC_COLOR,
-	D3D12_BLEND_DEST_COLOR,
-	D3D12_BLEND_INV_DEST_COLOR,
-	D3D12_BLEND_SRC_ALPHA,
-	D3D12_BLEND_INV_SRC_ALPHA,
-	D3D12_BLEND_DEST_ALPHA,
-	D3D12_BLEND_INV_DEST_ALPHA,
-	D3D12_BLEND_BLEND_FACTOR,
-	D3D12_BLEND_INV_BLEND_FACTOR,
-	D3D12_BLEND_BLEND_FACTOR,
-	D3D12_BLEND_INV_BLEND_FACTOR,
-	D3D12_BLEND_SRC_ALPHA_SAT,
-	D3D12_BLEND_SRC1_COLOR,
-	D3D12_BLEND_INV_SRC1_COLOR,
-	D3D12_BLEND_SRC1_ALPHA,
-	D3D12_BLEND_INV_SRC1_ALPHA,
-};
-
-const D3D12_BLEND_OP RenderingDeviceD3D12::blend_operations[RenderingDevice::BLEND_OP_MAX] = {
-	D3D12_BLEND_OP_ADD,
-	D3D12_BLEND_OP_SUBTRACT,
-	D3D12_BLEND_OP_REV_SUBTRACT,
-	D3D12_BLEND_OP_MIN,
-	D3D12_BLEND_OP_MAX,
-};
-
-const D3D12_TEXTURE_ADDRESS_MODE RenderingDeviceD3D12::address_modes[RenderingDevice::SAMPLER_REPEAT_MODE_MAX] = {
-	D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-	D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
-	D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
-	D3D12_TEXTURE_ADDRESS_MODE_BORDER,
-	D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
-};
-
-const FLOAT RenderingDeviceD3D12::sampler_border_colors[RenderingDevice::SAMPLER_BORDER_COLOR_MAX][4] = {
-	{ 0, 0, 0, 0 },
-	{ 0, 0, 0, 0 },
-	{ 0, 0, 0, 1 },
-	{ 0, 0, 0, 1 },
-	{ 1, 1, 1, 1 },
-	{ 1, 1, 1, 1 },
-};
-
-const D3D12_RESOURCE_DIMENSION RenderingDeviceD3D12::d3d12_texture_dimension[RenderingDevice::TEXTURE_TYPE_MAX] = {
-	D3D12_RESOURCE_DIMENSION_TEXTURE1D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE3D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE1D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
-	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
-};
-
-/******************/
-/**** RESOURCE ****/
-/******************/
-
-static const D3D12_RESOURCE_STATES RESOURCE_READ_STATES =
-		D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER |
-		D3D12_RESOURCE_STATE_INDEX_BUFFER |
-		D3D12_RESOURCE_STATE_DEPTH_READ |
-		D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
-		D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
-		D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT |
-		D3D12_RESOURCE_STATE_COPY_SOURCE |
-		D3D12_RESOURCE_STATE_RESOLVE_SOURCE |
-		D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE;
-
-static const D3D12_RESOURCE_STATES RESOURCE_WRITE_STATES =
-		D3D12_RESOURCE_STATE_RENDER_TARGET |
-		D3D12_RESOURCE_STATE_DEPTH_WRITE |
-		D3D12_RESOURCE_STATE_COPY_DEST |
-		D3D12_RESOURCE_STATE_RESOLVE_DEST;
-
-static const D3D12_RESOURCE_STATES RESOURCE_RW_STATES =
-		D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-
-void RenderingDeviceD3D12::ResourceState::extend(D3D12_RESOURCE_STATES p_states_to_add) {
-	states |= p_states_to_add;
-
-#ifdef DEV_ENABLED
-	if ((states & RESOURCE_RW_STATES)) {
-		if ((states & RESOURCE_READ_STATES)) {
-			// Thanks to [[SRV_UAV_AMBIGUITY]], this is not necessarily an error.
-		}
-		if ((states & RESOURCE_WRITE_STATES)) {
-			ERR_PRINT("Error in new state mask: has R/W state plus some W/O state(s).");
-		}
-	} else {
-		if ((states & RESOURCE_WRITE_STATES)) {
-			if ((states & RESOURCE_READ_STATES)) {
-				ERR_PRINT("Error in new state mask: mixes R/O and W/O states.");
-			} else {
-				uint32_t num_w_states = 0;
-				for (uint32_t i = 0; i < sizeof(D3D12_RESOURCE_STATES) * 8; i++) {
-					num_w_states += ((states & RESOURCE_WRITE_STATES) & (1 << i)) ? 1 : 0;
-				}
-				ERR_PRINT("Error in new state mask: has multiple W/O states.");
-			}
-		}
-	}
-#endif
-}
-
-void RenderingDeviceD3D12::_resource_transition_batch(Resource *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override) {
-	DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here.
-	DEV_ASSERT(p_new_state != D3D12_RESOURCE_STATE_COMMON); // No need to support this for now.
-
-#ifdef DEBUG_COUNT_BARRIERS
-	uint64_t start = OS::get_singleton()->get_ticks_usec();
-#endif
-
-	Resource::States *res_states = p_resource->get_states_ptr();
-	D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource];
-
-	ID3D12Resource *res_to_transition = p_resource_override ? p_resource_override : p_resource->resource;
-
-	bool redundant_transition = ((*curr_state) & p_new_state) == p_new_state;
-	if (redundant_transition) {
-		bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-		bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
-		if (needs_uav_barrier) {
-			if (res_barriers.size() < res_barriers_count + 1) {
-				res_barriers.resize(res_barriers_count + 1);
-			}
-			res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(res_to_transition);
-			res_barriers_count++;
-			res_states->last_batch_with_uav_barrier = res_barriers_batch;
-		}
-	} else {
-		uint64_t subres_mask_piece = ((uint64_t)1 << (p_subresource & 0b111111));
-		uint8_t subres_qword = p_subresource >> 6;
-
-		if (res_barriers_requests.has(res_states)) {
-			BarrierRequest &br = res_barriers_requests.get(res_states);
-			DEV_ASSERT(br.dx_resource == res_to_transition);
-			DEV_ASSERT(br.subres_mask_qwords == ALIGN(res_states->subresource_states.size(), 64) / 64);
-			DEV_ASSERT(br.planes == p_num_planes);
-
-			// First, find if the subresource already has a barrier scheduled.
-			uint8_t curr_group_idx = 0;
-			bool same_transition_scheduled = false;
-			for (curr_group_idx = 0; curr_group_idx < br.groups_count; curr_group_idx++) {
-				if (unlikely(br.groups[curr_group_idx].state.get_state_mask() == BarrierRequest::DELETED_GROUP)) {
-					continue;
-				}
-				if ((br.groups[curr_group_idx].subres_mask[subres_qword] & subres_mask_piece)) {
-					uint32_t state_mask = br.groups[curr_group_idx].state.get_state_mask();
-					same_transition_scheduled = (state_mask & (uint32_t)p_new_state) == (uint32_t)p_new_state;
-					break;
-				}
-			}
-			if (!same_transition_scheduled) {
-				bool subres_already_there = curr_group_idx != br.groups_count;
-				ResourceState final_state;
-				if (subres_already_there) {
-					final_state = br.groups[curr_group_idx].state;
-					final_state.extend(p_new_state);
-					bool subres_alone = true;
-					for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
-						if (i == subres_qword) {
-							if (br.groups[curr_group_idx].subres_mask[i] != subres_mask_piece) {
-								subres_alone = false;
-								break;
-							}
-						} else {
-							if (br.groups[curr_group_idx].subres_mask[i] != 0) {
-								subres_alone = false;
-								break;
-							}
-						}
-					}
-					bool relocated = false;
-					if (subres_alone) {
-						// Subresource is there by itself.
-						for (uint8_t i = 0; i < br.groups_count; i++) {
-							if (unlikely(i == curr_group_idx)) {
-								continue;
-							}
-							if (unlikely(br.groups[i].state.get_state_mask() == BarrierRequest::DELETED_GROUP)) {
-								continue;
-							}
-							// There's another group with the final state; relocate to it.
-							if (br.groups[i].state.get_state_mask() == final_state.get_state_mask()) {
-								br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
-								relocated = true;
-								break;
-							}
-						}
-						if (relocated) {
-							// Let's delete the group where it used to be by itself.
-							if (curr_group_idx == br.groups_count - 1) {
-								br.groups_count--;
-							} else {
-								br.groups[curr_group_idx].state = ResourceState(BarrierRequest::DELETED_GROUP);
-							}
-						} else {
-							// Its current group, where it's alone, can extend its state.
-							br.groups[curr_group_idx].state = final_state;
-						}
-					} else {
-						// Already there, but not by itself and the state mask is different, so it now belongs to a different group.
-						br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
-						subres_already_there = false;
-					}
-				} else {
-					final_state = p_new_state;
-				}
-				if (!subres_already_there) {
-					// See if it fits exactly the state of some of the groups to fit it there.
-					for (uint8_t i = 0; i < br.groups_count; i++) {
-						if (unlikely(i == curr_group_idx)) {
-							continue;
-						}
-						if (unlikely(br.groups[i].state.get_state_mask() == BarrierRequest::DELETED_GROUP)) {
-							continue;
-						}
-						if (br.groups[i].state.get_state_mask() == final_state.get_state_mask()) {
-							br.groups[i].subres_mask[subres_qword] |= subres_mask_piece;
-							subres_already_there = true;
-							break;
-						}
-					}
-					if (!subres_already_there) {
-						// Add a new group to accommodate this subresource.
-						uint8_t group_to_fill = 0;
-						if (br.groups_count < BarrierRequest::MAX_GROUPS) {
-							// There are still free groups.
-							group_to_fill = br.groups_count;
-							br.groups_count++;
-						} else {
-							// Let's try to take over a deleted one.
-							for (; group_to_fill < br.groups_count; group_to_fill++) {
-								if (unlikely(br.groups[group_to_fill].state.get_state_mask() == BarrierRequest::DELETED_GROUP)) {
-									break;
-								}
-							}
-							CRASH_COND(group_to_fill == br.groups_count);
-						}
-
-						br.groups[group_to_fill].state = final_state;
-						for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
-							if (unlikely(i == subres_qword)) {
-								br.groups[group_to_fill].subres_mask[i] = subres_mask_piece;
-							} else {
-								br.groups[group_to_fill].subres_mask[i] = 0;
-							}
-						}
-					}
-				}
-			}
-		} else {
-			BarrierRequest &br = res_barriers_requests[res_states];
-			br.dx_resource = res_to_transition;
-			br.subres_mask_qwords = ALIGN(p_resource->get_states_ptr()->subresource_states.size(), 64) / 64;
-			CRASH_COND(p_resource->get_states_ptr()->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES);
-			br.planes = p_num_planes;
-			br.groups[0].state = p_new_state;
-			for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
-				if (unlikely(i == subres_qword)) {
-					br.groups[0].subres_mask[i] = subres_mask_piece;
-				} else {
-					br.groups[0].subres_mask[i] = 0;
-				}
-			}
-			br.groups_count = 1;
-		}
-	}
-
-	if (p_new_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
-		res_states->last_batch_transitioned_to_uav = res_barriers_batch;
-	}
-
-#ifdef DEBUG_COUNT_BARRIERS
-	frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
-#endif
-}
-
-void RenderingDeviceD3D12::_resource_transitions_flush(ID3D12GraphicsCommandList *p_command_list) {
-#ifdef DEBUG_COUNT_BARRIERS
-	uint64_t start = OS::get_singleton()->get_ticks_usec();
-#endif
-
-	for (const KeyValue<Resource::States *, BarrierRequest> &E : res_barriers_requests) {
-		Resource::States *res_states = E.key;
-		const BarrierRequest &br = E.value;
-
-		uint32_t num_subresources = res_states->subresource_states.size();
-
-		// When there's not a lot of subresources, the empirical finding is that it's better
-		// to avoid attempting the single-barrier optimization.
-		static const uint32_t SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES = 48;
-
-		bool may_do_single_barrier = br.groups_count == 1 && num_subresources * br.planes >= SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES;
-		if (may_do_single_barrier) {
-			// A single group means we may be able to do a single all-subresources barrier.
-
-			{
-				// First requisite is that all subresources are involved.
-
-				uint8_t subres_mask_full_qwords = num_subresources / 64;
-				for (uint32_t i = 0; i < subres_mask_full_qwords; i++) {
-					if (br.groups[0].subres_mask[i] != UINT64_MAX) {
-						may_do_single_barrier = false;
-						break;
-					}
-				}
-				if (may_do_single_barrier) {
-					if (num_subresources % 64) {
-						DEV_ASSERT(br.subres_mask_qwords == subres_mask_full_qwords + 1);
-						uint64_t mask_tail_qword = 0;
-						for (uint8_t i = 0; i < num_subresources % 64; i++) {
-							mask_tail_qword |= ((uint64_t)1 << i);
-						}
-						if ((br.groups[0].subres_mask[subres_mask_full_qwords] & mask_tail_qword) != mask_tail_qword) {
-							may_do_single_barrier = false;
-						}
-					}
-				}
-			}
-
-			if (may_do_single_barrier) {
-				// Second requisite is that the source state is the same for all.
-
-				for (uint32_t i = 1; i < num_subresources; i++) {
-					if (res_states->subresource_states[i] != res_states->subresource_states[0]) {
-						may_do_single_barrier = false;
-						break;
-					}
-				}
-
-				if (may_do_single_barrier) {
-					// Hurray!, we can do a single barrier (plus maybe a UAV one, too).
-
-					bool just_written = res_states->subresource_states[0] == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
-
-					uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + 1;
-					if (res_barriers.size() < res_barriers_count + needed_barriers) {
-						res_barriers.resize(res_barriers_count + needed_barriers);
-					}
-
-					if (needs_uav_barrier) {
-						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
-						res_barriers_count++;
-						res_states->last_batch_with_uav_barrier = res_barriers_batch;
-					}
-
-					if (res_states->subresource_states[0] != br.groups[0].state.get_state_mask()) {
-						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].state.get_state_mask(), D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
-						res_barriers_count++;
-					}
-
-					for (uint32_t i = 0; i < num_subresources; i++) {
-						res_states->subresource_states[i] = br.groups[0].state.get_state_mask();
-					}
-				}
-			}
-		}
-
-		if (!may_do_single_barrier) {
-			for (uint8_t i = 0; i < br.groups_count; i++) {
-				const BarrierRequest::Group &g = E.value.groups[i];
-
-				if (unlikely(g.state.get_state_mask() == BarrierRequest::DELETED_GROUP)) {
-					continue;
-				}
-
-				uint32_t subresource = 0;
-				do {
-					uint64_t subres_mask_piece = ((uint64_t)1 << (subresource % 64));
-					uint8_t subres_qword = subresource / 64;
-
-					if (likely(g.subres_mask[subres_qword] == 0)) {
-						subresource += 64;
-						continue;
-					}
-
-					if (likely(!(g.subres_mask[subres_qword] & subres_mask_piece))) {
-						subresource++;
-						continue;
-					}
-
-					D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[subresource];
-
-					bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
-
-					uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + br.planes;
-					if (res_barriers.size() < res_barriers_count + needed_barriers) {
-						res_barriers.resize(res_barriers_count + needed_barriers);
-					}
-
-					if (needs_uav_barrier) {
-						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
-						res_barriers_count++;
-						res_states->last_batch_with_uav_barrier = res_barriers_batch;
-					}
-
-					if (*curr_state != g.state.get_state_mask()) {
-						for (uint8_t k = 0; k < br.planes; k++) {
-							res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.state.get_state_mask(), subresource + k * num_subresources);
-							res_barriers_count++;
-						}
-					}
-
-					*curr_state = g.state.get_state_mask();
-
-					subresource++;
-				} while (subresource < num_subresources);
-			}
-		}
-	}
-
-	if (res_barriers_count) {
-		p_command_list->ResourceBarrier(res_barriers_count, res_barriers.ptr());
-		res_barriers_requests.clear();
-	}
-
-#ifdef DEBUG_COUNT_BARRIERS
-	frame_barriers_count += res_barriers_count;
-	frame_barriers_batches_count++;
-	frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
-#endif
-
-	res_barriers_count = 0;
-	res_barriers_batch++;
-}
-
-/***************************/
-/**** BUFFER MANAGEMENT ****/
-/***************************/
-
-Error RenderingDeviceD3D12::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, D3D12_RESOURCE_STATES p_usage, D3D12_HEAP_TYPE p_heap_type) {
-	ERR_FAIL_COND_V(p_heap_type != D3D12_HEAP_TYPE_DEFAULT && p_heap_type != D3D12_HEAP_TYPE_READBACK, ERR_INVALID_PARAMETER);
-
-	// D3D12 debug layers complain at CBV creation time if the size is not multiple of the value per the spec
-	// but also if you give a rounded size at that point because it will extend beyond the
-	// memory of the resource. Therefore, it seems the only way is to create it with a
-	// rounded size.
-	CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(ALIGN(p_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT));
-	if ((p_usage & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
-		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-	}
-
-	D3D12MA::ALLOCATION_DESC allocation_desc = {};
-	allocation_desc.HeapType = p_heap_type;
-#ifdef USE_SMALL_ALLOCS_POOL
-	if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
-		allocation_desc.CustomPool = _find_or_create_small_allocs_pool(p_heap_type, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS);
-	}
-#endif
-
-	HRESULT res = context->get_allocator()->CreateResource(
-			&allocation_desc,
-			&resource_desc,
-			D3D12_RESOURCE_STATE_COPY_DEST,
-			nullptr,
-			&p_buffer->allocation,
-			IID_PPV_ARGS(&p_buffer->resource));
-	ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size) + ", error " + vformat("0x%08ux", res) + ".");
-
-	p_buffer->size = p_size;
-	p_buffer->usage = p_usage;
-	p_buffer->own_states.subresource_states.push_back(D3D12_RESOURCE_STATE_COPY_DEST);
-
-	buffer_memory += p_size;
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::_buffer_free(Buffer *p_buffer) {
-	ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER);
-
-	buffer_memory -= p_buffer->size;
-
-	p_buffer->resource->Release();
-	p_buffer->resource = nullptr;
-	p_buffer->allocation->Release();
-	p_buffer->allocation = nullptr;
-	p_buffer->size = 0;
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::_insert_staging_block() {
-	StagingBufferBlock block;
-
-	D3D12_RESOURCE_DESC resource_desc = {};
-	resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
-	resource_desc.Alignment = 0;
-	resource_desc.Width = staging_buffer_block_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;
-
-	D3D12MA::ALLOCATION_DESC allocation_desc = {};
-	allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
-
-	HRESULT res = context->get_allocator()->CreateResource(
-			&allocation_desc,
-			&resource_desc,
-			D3D12_RESOURCE_STATE_GENERIC_READ,
-			NULL,
-			&block.allocation,
-			IID_PPV_ARGS(&block.resource));
-	ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "CreateResource failed with error " + vformat("0x%08ux", res) + ".");
-
-	staging_buffer_blocks.insert(staging_buffer_current, block);
-	return OK;
-}
-
-Error RenderingDeviceD3D12::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) {
-	// Determine a block to use.
-
-	r_alloc_size = p_amount;
-
-	while (true) {
-		r_alloc_offset = 0;
-
-		// See if we can use current block.
-		if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
-			// We used this block this frame, let's see if there is still room.
-
-			uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount;
-
-			{
-				uint32_t align_remainder = write_from % p_required_align;
-				if (align_remainder != 0) {
-					write_from += p_required_align - align_remainder;
-				}
-			}
-
-			int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from);
-
-			if ((int32_t)p_amount < available_bytes) {
-				// All is good, we should be ok, all will fit.
-				r_alloc_offset = write_from;
-			} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {
-				// Ok all won't fit but at least we can fit a chunkie.
-				// All is good, update what needs to be written to.
-				r_alloc_offset = write_from;
-				r_alloc_size = available_bytes - (available_bytes % p_required_align);
-
-			} else {
-				// Can't fit it into this buffer.
-				// Will need to try next buffer.
-
-				staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
-
-				// Before doing anything, though, let's check that we didn't manage to fill all functions.
-				// Possible in a single frame.
-				if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
-					// Guess we did.. ok, let's see if we can insert a new block.
-					if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
-						// We can, so we are safe.
-						Error err = _insert_staging_block();
-						if (err) {
-							return err;
-						}
-						// Claim for this frame.
-						staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-					} else {
-						// Ok, worst case scenario, all the staging buffers belong to this frame
-						// and this frame is not even done
-						// If this is the main thread, it means the user is likely loading a lot of resources at once,.
-						// Otherwise, the thread should just be blocked until the next frame (currently unimplemented).
-
-						if (false) { // Separate thread from render.
-
-							//block_until_next_frame()
-							continue;
-						} else {
-							// Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
-							_flush(true);
-
-							// Clear the whole staging buffer.
-							for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-								staging_buffer_blocks.write[i].frame_used = 0;
-								staging_buffer_blocks.write[i].fill_amount = 0;
-							}
-							// Claim current.
-							staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-						}
-					}
-
-				} else {
-					// Not from current frame, so continue and try again.
-					continue;
-				}
-			}
-
-		} else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) {
-			// This is an old block, which was already processed, let's reuse.
-			staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-			staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
-		} else {
-			// This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
-			if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
-				// We are still allowed to create a new block, so let's do that and insert it for current pos.
-				Error err = _insert_staging_block();
-				if (err) {
-					return err;
-				}
-				// Claim for this frame.
-				staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-			} else {
-				// Oops, we are out of room and we can't create more.
-				// Let's flush older frames.
-				// The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway.
-				// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).
-
-				if (false) {
-					// Separate thread from render.
-					//block_until_next_frame()
-					continue; // And try again.
-				} else {
-					_flush(false);
-
-					for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-						// Clear all functions but the ones from this frame.
-						int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
-						if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
-							break; // Ok, we reached something from this frame, abort.
-						}
-
-						staging_buffer_blocks.write[block_idx].frame_used = 0;
-						staging_buffer_blocks.write[block_idx].fill_amount = 0;
-					}
-
-					// Claim for current frame.
-					staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-				}
-			}
-		}
-
-		// All was good, break.
-		break;
-	}
-
-	staging_buffer_used = true;
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_list, uint32_t p_required_align) {
-	// Submitting may get chunked for various reasons, so convert this to a task.
-	size_t to_submit = p_data_size;
-	size_t submit_from = 0;
-
-	while (to_submit > 0) {
-		uint32_t block_write_offset;
-		uint32_t block_write_amount;
-
-		Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount);
-		if (err) {
-			return err;
-		}
-
-		// Map staging buffer.
-
-		void *data_ptr = nullptr;
-		{
-			HRESULT res = staging_buffer_blocks[staging_buffer_current].resource->Map(0, &VOID_RANGE, &data_ptr);
-			ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "Map failed with error " + vformat("0x%08ux", res) + ".");
-		}
-
-		// Copy to staging buffer.
-		memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
-
-		// Unmap.
-		staging_buffer_blocks[staging_buffer_current].resource->Unmap(0, &VOID_RANGE);
-
-		// Insert a command to copy this.
-		ID3D12GraphicsCommandList *command_list = (p_use_draw_command_list ? frames[frame].draw_command_list : frames[frame].setup_command_list).Get();
-		command_list->CopyBufferRegion(p_buffer->resource, submit_from + p_offset, staging_buffer_blocks[staging_buffer_current].resource, block_write_offset, block_write_amount);
-
-		staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount;
-
-		to_submit -= block_write_amount;
-		submit_from += block_write_amount;
-	}
-
-	return OK;
-}
-
-/*****************/
-/**** TEXTURE ****/
-/*****************/
-
-RID RenderingDeviceD3D12::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	D3D12_RESOURCE_DESC1 resource_desc = {}; // Using D3D12_RESOURCE_DESC1. Thanks to the layout, it's sliceable down to D3D12_RESOURCE_DESC if needed.
-	resource_desc.Alignment = 0; // D3D12MA will override this to use a smaller alignment than the default if possible.
-
-	Vector<DataFormat> allowed_formats;
-	if (p_format.shareable_formats.size()) {
-		ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(),
-				"If supplied a list of shareable formats, the current format must be present in the list");
-		ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(),
-				"If supplied a list of shareable formats, the current view format override must be present in the list");
-		allowed_formats = p_format.shareable_formats;
-	} else {
-		allowed_formats.push_back(p_format.format);
-		if (p_view.format_override != DATA_FORMAT_MAX) {
-			allowed_formats.push_back(p_view.format_override);
-		}
-	}
-
-	ERR_FAIL_INDEX_V(p_format.texture_type, TEXTURE_TYPE_MAX, RID());
-
-	resource_desc.Dimension = d3d12_texture_dimension[p_format.texture_type];
-
-	ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");
-
-	resource_desc.Format = d3d12_formats[p_format.format].family;
-
-	resource_desc.Width = p_format.width;
-	if (resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D || resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D) {
-		ERR_FAIL_COND_V_MSG(p_format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures");
-		resource_desc.Height = p_format.height;
-	} else {
-		resource_desc.Height = 1;
-	}
-
-	if (resource_desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) {
-		ERR_FAIL_COND_V_MSG(p_format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures");
-		resource_desc.DepthOrArraySize = p_format.depth;
-	} else {
-		resource_desc.DepthOrArraySize = 1;
-	}
-
-	ERR_FAIL_COND_V(p_format.mipmaps < 1, RID());
-
-	resource_desc.MipLevels = p_format.mipmaps;
-
-	if (p_format.texture_type == TEXTURE_TYPE_1D_ARRAY || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) {
-		ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(),
-				"Amount of layers must be equal or greater than 1 for arrays and cubemaps.");
-		ERR_FAIL_COND_V_MSG((p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(),
-				"Cubemap and cubemap array textures must provide a layer number that is multiple of 6");
-		resource_desc.DepthOrArraySize *= p_format.array_layers;
-	}
-
-	ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID());
-
-	// Usage.
-
-	if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
-	} else {
-		if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT)) {
-			resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // For clearing via UAV.
-		}
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) {
-		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-	}
-
-	resource_desc.SampleDesc = {};
-	DXGI_FORMAT format_to_test = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ? d3d12_formats[p_format.format].dsv_format : d3d12_formats[p_format.format].general_format;
-	if (!(resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
-		resource_desc.SampleDesc.Count = MIN(
-				_find_max_common_supported_sample_count(&format_to_test, 1),
-				rasterization_sample_count[p_format.samples]);
-	} else {
-		// No MSAA in D3D12 if storage. May have become possible recently where supported, though.
-		resource_desc.SampleDesc.Count = 1;
-	}
-	resource_desc.SampleDesc.Quality = resource_desc.SampleDesc.Count == 1 ? 0 : DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
-
-	uint32_t required_mipmaps = get_image_required_mipmaps(p_format.width, p_format.height, p_format.depth);
-
-	ERR_FAIL_COND_V_MSG(required_mipmaps < p_format.mipmaps, RID(),
-			"Too many mipmaps requested for texture format and dimensions (" + itos(p_format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ").");
-
-	if (p_data.size()) {
-		ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(),
-				"Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later");
-
-		int expected_images = p_format.array_layers;
-		ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(),
-				"Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ").");
-
-		for (uint32_t i = 0; i < p_format.array_layers; i++) {
-			uint32_t required_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps);
-			ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(),
-					"Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ").");
-		}
-	}
-
-	// Validate that this image is supported for the intended use.
-
-	// If views of different families are wanted, special setup is needed for proper sharing among them.
-	// Two options here:
-	// 1. If ID3DDevice10 is present and driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA).
-	// 2. Otherwise, fall back to an approach based on abusing aliasing, hoping for the best.
-	bool cross_family_sharing = false;
-	ComPtr<ID3D12Device10> device10;
-	device.As(&device10);
-	bool relaxed_casting_available = device10.Get() && context->get_format_capabilities().relaxed_casting_supported;
-	LocalVector<DXGI_FORMAT> castable_formats;
-
-	HashMap<DataFormat, D3D12_RESOURCE_FLAGS> aliases_forbidden_flags;
-	D3D12_RESOURCE_FLAGS accum_forbidden_flags = {};
-	for (DataFormat curr_format : allowed_formats) {
-		// For now, we'll validate usages only the main format, to match what Vulkan RD does.
-		// TODO: The aliasing trick assumes the main format is the only writable one. We should either validate for that or handle a different order gracefully.
-		bool checking_main_format = curr_format == p_format.format;
-
-		String format_text = "'" + String(named_formats[p_format.format]) + "'";
-
-		ERR_FAIL_COND_V_MSG(d3d12_formats[curr_format].family == DXGI_FORMAT_UNKNOWN, RID(), "Format " + format_text + " is not supported.");
-
-		if (d3d12_formats[curr_format].family != d3d12_formats[allowed_formats[0]].family) {
-			cross_family_sharing = true;
-		}
-		if (relaxed_casting_available) {
-			castable_formats.push_back(d3d12_formats[curr_format].general_format);
-		}
-
-		D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
-		srv_rtv_support.Format = d3d12_formats[curr_format].general_format;
-		HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
-		ERR_FAIL_COND_V_MSG(res, RID(), "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
-
-		D3D12_FEATURE_DATA_FORMAT_SUPPORT uav_support = srv_rtv_support; // Fine for now.
-
-		D3D12_FEATURE_DATA_FORMAT_SUPPORT dsv_support = {};
-		dsv_support.Format = d3d12_formats[curr_format].dsv_format;
-		res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dsv_support, sizeof(dsv_support));
-		ERR_FAIL_COND_V_MSG(res, RID(), "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
-
-		if (checking_main_format) {
-			if ((p_format.usage_bits & (TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) {
-				if (p_format.mipmaps && !(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_MIP)) {
-					ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support mip.maps.");
-				}
-			}
-
-			// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_format_support1,
-			// as long as the resource can be used as a texture, Sample() will work with point filter at least.
-			// However, we've empirically found that checking for at least D3D12_FORMAT_SUPPORT1_SHADER_LOAD is needed.
-			// That's almost good for integer formats. The problem is that theoretically there may be
-			// float formats that support LOAD but not SAMPLE fully, so this check will not detect
-			// such a flaw in the format. Linearly interpolated sampling would just not work on them.
-			// [[IMPLICIT_SAMPLE]]
-			if ((p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) && !(srv_rtv_support.Support1 & (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE))) {
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as a sampled texture.");
-			}
-
-			if ((p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) && d3d12_formats[curr_format].general_format == DXGI_FORMAT_UNKNOWN) {
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as a sampled texture.");
-			}
-
-			if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment.");
-			}
-		}
-
-		if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT)) {
-			// We need to check if the texture can be cleared; if it's not flagged for color attachment , we have to see if it's possible via a UAV.
-			if (!(p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-				if (!(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) {
-					if (checking_main_format) {
-						ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as a copy-to texture, because clearing it is not supported.");
-					} else {
-						aliases_forbidden_flags[curr_format] |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-						accum_forbidden_flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-					}
-				}
-			}
-		}
-
-		if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(dsv_support.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {
-			if (checking_main_format) {
-				printf("dxgiformat: %x\n", resource_desc.Format);
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");
-			} else {
-				aliases_forbidden_flags[curr_format] |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
-				accum_forbidden_flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
-			}
-		}
-
-		if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
-			if (!(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { // Maybe check LOAD/STORE, too?
-				if (checking_main_format) {
-					ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image.");
-				} else {
-					aliases_forbidden_flags[curr_format] |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-					accum_forbidden_flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
-				}
-			}
-		}
-
-		if (checking_main_format) {
-			if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !(uav_support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD)) { // Check a basic atomic at least.
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");
-			}
-
-			if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && d3d12_formats[curr_format].general_format != DXGI_FORMAT_R8_UINT) {
-				ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as VRS attachment.");
-			}
-		}
-	}
-
-	if (cross_family_sharing && !relaxed_casting_available) {
-		// At least guarantee the same layout among aliases.
-		resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
-
-		// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_layout.
-		if (p_format.texture_type == TEXTURE_TYPE_1D) {
-			ERR_FAIL_V_MSG(RID(), "This texture's views require aliasing, but that's not supported for a 1D texture.");
-		}
-		if (p_format.samples != TEXTURE_SAMPLES_1) {
-			ERR_FAIL_V_MSG(RID(), "This texture's views require aliasing, but that's not supported for a multi-sample texture.");
-		}
-		if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "This texture's views require aliasing, but that's not supported for a depth-stencil texture.");
-		}
-		if (d3d12_formats[p_format.format].family == DXGI_FORMAT_R32G32B32_TYPELESS) {
-			ERR_FAIL_V_MSG(RID(), "This texture's views require aliasing, but that's not supported for an R32G32B32 texture.");
-		}
-	} else {
-		resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
-	}
-
-	if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {
-		// For VRS images we can't use the typeless format.
-		resource_desc.Format = DXGI_FORMAT_R8_UINT;
-	}
-
-	// Some view validation.
-
-	if (p_view.format_override != DATA_FORMAT_MAX) {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-	}
-	ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());
-
-	// Allocate memory.
-
-	D3D12MA::ALLOCATION_DESC allocation_desc = {};
-	if (cross_family_sharing && !relaxed_casting_available) {
-		allocation_desc.Flags = D3D12MA::ALLOCATION_FLAG_CAN_ALIAS;
-	}
-	allocation_desc.HeapType = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_DEFAULT;
-	if ((resource_desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) {
-		if (!(accum_forbidden_flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) {
-			allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
-		}
-	} else {
-		allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
-	}
-	if ((resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
-		if (!(accum_forbidden_flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
-			allocation_desc.ExtraHeapFlags |= D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS;
-		}
-	}
-
-#ifdef USE_SMALL_ALLOCS_POOL
-	uint32_t width, height;
-	uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
-	if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
-		allocation_desc.CustomPool = _find_or_create_small_allocs_pool(allocation_desc.HeapType, allocation_desc.ExtraHeapFlags);
-	}
-#endif
-
-	Texture texture;
-
-	D3D12_RESOURCE_STATES initial_state = p_data.size() || (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
-	FLOAT black[4] = {};
-	D3D12_CLEAR_VALUE clear_value = CD3DX12_CLEAR_VALUE(d3d12_formats[p_format.format].general_format, black);
-	D3D12_CLEAR_VALUE *clear_value_ptr = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : nullptr;
-	HRESULT res = {};
-	if (cross_family_sharing && relaxed_casting_available) {
-		res = context->get_allocator()->CreateResource3(
-				&allocation_desc,
-				&resource_desc,
-				D3D12_BARRIER_LAYOUT_COMMON, // Needed for barrier interop.
-				clear_value_ptr,
-				castable_formats.size(),
-				castable_formats.ptr(),
-				&texture.allocation,
-				IID_PPV_ARGS(&texture.owner_resource));
-		initial_state = D3D12_RESOURCE_STATE_COMMON; // Needed for barrier interop.
-	} else {
-		res = context->get_allocator()->CreateResource(
-				&allocation_desc,
-				(D3D12_RESOURCE_DESC *)&resource_desc,
-				initial_state,
-				clear_value_ptr,
-				&texture.allocation,
-				IID_PPV_ARGS(&texture.owner_resource));
-	}
-	ERR_FAIL_COND_V_MSG(res, RID(), "CreateResource failed with error " + vformat("0x%08ux", res) + ".");
-	texture.resource = texture.owner_resource;
-	image_memory += texture.allocation->GetSize();
-	texture.type = p_format.texture_type;
-	texture.format = p_format.format;
-	texture.planes = get_image_format_plane_count(p_format.format);
-	texture.width = p_format.width;
-	texture.height = p_format.height;
-	texture.depth = p_format.depth;
-	texture.layers = p_format.array_layers;
-	texture.mipmaps = p_format.mipmaps;
-	texture.owner_layers = texture.layers;
-	texture.owner_mipmaps = texture.mipmaps;
-	texture.base_mipmap = 0;
-	texture.base_layer = 0;
-	texture.is_resolve_buffer = p_format.is_resolve_buffer;
-	texture.usage_flags = p_format.usage_bits;
-	texture.samples = p_format.samples;
-	texture.allowed_shared_formats = p_format.shareable_formats;
-	texture.own_states.subresource_states.resize(texture.mipmaps * texture.layers);
-	for (uint32_t i = 0; i < texture.own_states.subresource_states.size(); i++) {
-		texture.own_states.subresource_states[i] = initial_state;
-	}
-	texture.bound = false;
-
-	// Describe view.
-
-	static const D3D12_SRV_DIMENSION view_dimensions[TEXTURE_TYPE_MAX] = {
-		D3D12_SRV_DIMENSION_TEXTURE1D,
-		D3D12_SRV_DIMENSION_TEXTURE2D,
-		D3D12_SRV_DIMENSION_TEXTURE3D,
-		D3D12_SRV_DIMENSION_TEXTURECUBE,
-		D3D12_SRV_DIMENSION_TEXTURE1DARRAY,
-		D3D12_SRV_DIMENSION_TEXTURE2DARRAY,
-		D3D12_SRV_DIMENSION_TEXTURECUBEARRAY,
-	};
-	static const D3D12_SRV_DIMENSION view_dimensions_ms[TEXTURE_TYPE_MAX] = {
-		D3D12_SRV_DIMENSION_UNKNOWN,
-		D3D12_SRV_DIMENSION_TEXTURE2DMS,
-		D3D12_SRV_DIMENSION_UNKNOWN,
-		D3D12_SRV_DIMENSION_UNKNOWN,
-		D3D12_SRV_DIMENSION_UNKNOWN,
-		D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY,
-		D3D12_SRV_DIMENSION_UNKNOWN,
-	};
-	static const D3D12_UAV_DIMENSION uav_dimensions[TEXTURE_TYPE_MAX] = {
-		D3D12_UAV_DIMENSION_TEXTURE1D,
-		D3D12_UAV_DIMENSION_TEXTURE2D,
-		D3D12_UAV_DIMENSION_TEXTURE3D,
-		D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
-		D3D12_UAV_DIMENSION_TEXTURE1DARRAY,
-		D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
-		D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
-	};
-
-	texture.srv_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? view_dimensions[p_format.texture_type] : view_dimensions_ms[p_format.texture_type];
-
-	texture.owner_uav_desc.Format = d3d12_formats[p_format.format].general_format;
-	texture.owner_uav_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? uav_dimensions[p_format.texture_type] : D3D12_UAV_DIMENSION_UNKNOWN;
-
-	UINT base_swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-	if (p_view.format_override == DATA_FORMAT_MAX) {
-		texture.srv_desc.Format = d3d12_formats[p_format.format].general_format;
-		base_swizzle = d3d12_formats[p_format.format].swizzle;
-	} else {
-		texture.srv_desc.Format = d3d12_formats[p_view.format_override].general_format;
-		base_swizzle = d3d12_formats[p_view.format_override].swizzle;
-	}
-
-	// Apply requested swizzle (component mapping) on top of the one from the format database.
-
-	D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
-		// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),
-	};
-
-	texture.srv_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
-			p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],
-			p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],
-			p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],
-			p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);
-
-	switch (texture.srv_desc.ViewDimension) {
-		case D3D12_SRV_DIMENSION_TEXTURE1D: {
-			texture.srv_desc.Texture1D.MipLevels = p_format.mipmaps;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
-			texture.srv_desc.Texture1DArray.MipLevels = p_format.mipmaps;
-			texture.srv_desc.Texture1DArray.ArraySize = p_format.array_layers;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2D: {
-			texture.srv_desc.Texture2D.MipLevels = p_format.mipmaps;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
-			texture.srv_desc.Texture2DArray.MipLevels = p_format.mipmaps;
-			texture.srv_desc.Texture2DArray.ArraySize = p_format.array_layers;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
-			texture.srv_desc.Texture2DMSArray.ArraySize = p_format.array_layers;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
-			texture.srv_desc.TextureCubeArray.MipLevels = p_format.mipmaps;
-			texture.srv_desc.TextureCubeArray.NumCubes = p_format.array_layers / 6;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE3D: {
-			texture.srv_desc.Texture3D.MipLevels = p_format.mipmaps;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURECUBE: {
-			texture.srv_desc.TextureCube.MipLevels = p_format.mipmaps;
-		} break;
-	}
-
-	switch (texture.owner_uav_desc.ViewDimension) {
-		case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
-			texture.owner_uav_desc.Texture1DArray.ArraySize = p_format.array_layers;
-		} break;
-		case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
-			// Either for an actual 2D texture array, cubemap or cubemap array.
-			texture.owner_uav_desc.Texture2DArray.ArraySize = p_format.array_layers;
-		} break;
-		case D3D12_UAV_DIMENSION_TEXTURE3D: {
-			texture.owner_uav_desc.Texture3D.WSize = p_format.depth;
-		} break;
-		default: {
-		}
-	}
-
-	texture.uav_desc = texture.owner_uav_desc;
-	if (p_view.format_override != DATA_FORMAT_MAX) {
-		texture.uav_desc.Format = d3d12_formats[p_view.format_override].general_format;
-	}
-
-	if (cross_family_sharing && !relaxed_casting_available) {
-		D3D12_RESOURCE_DESC resource_desc_backup = *(D3D12_RESOURCE_DESC *)&resource_desc;
-		D3D12MA::ALLOCATION_DESC allocation_desc_backup = allocation_desc;
-
-		texture.aliases.resize(texture.allowed_shared_formats.size());
-		for (int i = 0; i < texture.allowed_shared_formats.size(); i++) {
-			DataFormat curr_format = texture.allowed_shared_formats[i];
-
-			DXGI_FORMAT format_family = d3d12_formats[curr_format].family;
-			if (format_family == d3d12_formats[p_format.format].family) {
-				texture.aliases[i] = nullptr;
-				continue;
-			}
-
-			D3D12_RESOURCE_DESC alias_resource_desc = *(D3D12_RESOURCE_DESC *)&resource_desc;
-			alias_resource_desc.Format = format_family;
-			if (aliases_forbidden_flags.has(curr_format)) {
-				alias_resource_desc.Flags &= ~aliases_forbidden_flags[curr_format];
-			}
-			clear_value.Format = format_family;
-			res = context->get_allocator()->CreateAliasingResource(
-					texture.allocation,
-					0,
-					&alias_resource_desc,
-					initial_state,
-					(alias_resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? clear_value_ptr : nullptr,
-					IID_PPV_ARGS(&texture.aliases[i]));
-			ERR_FAIL_COND_V_MSG(res, RID(), "CreateAliasingResource failed with error " + vformat("0x%08ux", res) + ".");
-
-			if (curr_format == p_view.format_override) {
-				texture.resource = texture.aliases[i];
-			}
-		}
-	}
-
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-
-	if (p_data.size()) {
-		Texture *texture_ptr = texture_owner.get_or_null(id);
-		ERR_FAIL_NULL_V(texture_ptr, RID());
-
-		ID3D12GraphicsCommandList *command_list = frames[frame].setup_command_list.Get();
-
-		for (uint32_t i = 0; i < p_format.array_layers; i++) {
-			_texture_update(texture_ptr, i, p_data[i], RD::BARRIER_MASK_ALL_BARRIERS, command_list);
-		}
-	}
-	return id;
-}
-
-RID RenderingDeviceD3D12::texture_create_shared(const TextureView &p_view, RID p_with_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_texture = texture_owner.get_or_null(p_with_texture);
-	ERR_FAIL_NULL_V(src_texture, RID());
-
-	if (src_texture->owner.is_valid()) { // Ahh this is a share.
-		p_with_texture = src_texture->owner;
-		src_texture = texture_owner.get_or_null(src_texture->owner);
-		ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
-	}
-
-	// Describe view.
-
-	Texture texture = *src_texture;
-	texture.own_states.subresource_states.clear();
-	texture.states = &src_texture->own_states;
-
-	UINT base_swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-	if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
-		texture.srv_desc.Format = d3d12_formats[texture.format].general_format;
-		base_swizzle = d3d12_formats[texture.format].swizzle;
-		texture.uav_desc.Format = d3d12_formats[texture.format].general_format;
-	} else {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-
-		ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
-				"Format override is not in the list of allowed shareable formats for original texture.");
-		texture.srv_desc.Format = d3d12_formats[p_view.format_override].general_format;
-		base_swizzle = d3d12_formats[p_view.format_override].swizzle;
-		texture.uav_desc.Format = d3d12_formats[p_view.format_override].general_format;
-
-		if (texture.aliases.size()) {
-			for (int i = 0; i < texture.allowed_shared_formats.size(); i++) {
-				if (texture.allowed_shared_formats[i] == p_view.format_override) {
-					texture.resource = texture.aliases[i];
-					break;
-				}
-			}
-		}
-	}
-
-	// Apply requested swizzle (component mapping) on top of the one from the format database.
-
-	D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
-		// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),
-	};
-
-	texture.srv_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
-			p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],
-			p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],
-			p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],
-			p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);
-
-	texture.owner = p_with_texture;
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	_add_dependency(id, p_with_texture);
-
-	return id;
-}
-
-RID RenderingDeviceD3D12::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) {
-	ERR_FAIL_V_MSG(RID(), "Unimplemented!");
-}
-
-RID RenderingDeviceD3D12::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type, uint32_t p_layers) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_texture = texture_owner.get_or_null(p_with_texture);
-	ERR_FAIL_NULL_V(src_texture, RID());
-
-	if (src_texture->owner.is_valid()) { // Ahh this is a share.
-		p_with_texture = src_texture->owner;
-		src_texture = texture_owner.get_or_null(src_texture->owner);
-		ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
-	}
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
-			"Can only create a cubemap slice from a cubemap or cubemap array mipmap");
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(),
-			"Can only create a 3D slice from a 3D texture");
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(),
-			"Can only create an array slice from a 2D array mipmap");
-
-	// Describe view.
-
-	ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());
-	ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());
-	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID());
-
-	int slice_layers = 1;
-	if (p_layers != 0) {
-		ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays");
-		ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds");
-		slice_layers = p_layers;
-	} else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) {
-		ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice");
-		slice_layers = src_texture->layers;
-	} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
-		slice_layers = 6;
-	}
-
-	Texture texture = *src_texture;
-	get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
-	texture.mipmaps = p_mipmaps;
-	texture.layers = slice_layers;
-	texture.base_mipmap = p_mipmap;
-	texture.base_layer = p_layer;
-	texture.own_states.subresource_states.clear();
-	texture.states = &src_texture->own_states;
-
-	UINT base_swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-	if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
-		texture.srv_desc.Format = d3d12_formats[texture.format].general_format;
-		base_swizzle = d3d12_formats[texture.format].swizzle;
-		texture.uav_desc.Format = d3d12_formats[texture.format].general_format;
-	} else {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-
-		ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
-				"Format override is not in the list of allowed shareable formats for original texture.");
-		texture.srv_desc.Format = d3d12_formats[p_view.format_override].general_format;
-		base_swizzle = d3d12_formats[p_view.format_override].swizzle;
-		texture.uav_desc.Format = d3d12_formats[p_view.format_override].general_format;
-
-		if (texture.aliases.size()) {
-			for (int i = 0; i < texture.allowed_shared_formats.size(); i++) {
-				if (texture.allowed_shared_formats[i] == p_view.format_override) {
-					texture.resource = texture.aliases[i];
-					break;
-				}
-			}
-		}
-	}
-
-	// Apply requested swizzle (component mapping) on top of the one from the format database.
-
-	D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
-		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
-		// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),
-		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),
-	};
-
-	texture.srv_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
-			p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],
-			p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],
-			p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],
-			p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);
-
-	if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
-		ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(),
-				"Specified layer is invalid for cubemap");
-		ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(),
-				"Specified layer must be a multiple of 6.");
-	}
-
-	// Leveraging aliasing in members of the union as much as possible.
-
-	texture.srv_desc.Texture1D.MostDetailedMip = p_mipmap;
-	texture.srv_desc.Texture1D.MipLevels = 1;
-
-	texture.uav_desc.Texture1D.MipSlice = p_mipmap;
-
-	switch (p_slice_type) {
-		case TEXTURE_SLICE_2D: {
-			if (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) {
-				CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE2D);
-			} else if (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) {
-				CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_UNKNOWN);
-			} else if ((texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) {
-				texture.srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
-				texture.srv_desc.Texture2DArray.FirstArraySlice = p_layer;
-				texture.srv_desc.Texture2DArray.ArraySize = 1;
-				texture.srv_desc.Texture2DArray.PlaneSlice = 0;
-				texture.srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
-
-				texture.uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
-				texture.uav_desc.Texture2DArray.FirstArraySlice = p_layer;
-				texture.uav_desc.Texture2DArray.ArraySize = 1;
-				texture.uav_desc.Texture2DArray.PlaneSlice = 0;
-			} else if ((texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) {
-				texture.srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
-				texture.srv_desc.Texture2DMSArray.FirstArraySlice = p_layer;
-				texture.srv_desc.Texture2DMSArray.ArraySize = 1;
-
-				texture.uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN;
-			} else {
-				CRASH_NOW();
-			}
-		} break;
-		case TEXTURE_SLICE_CUBEMAP: {
-			if (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE) {
-				CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
-			} else if (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) {
-				texture.srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
-
-				CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
-				texture.uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
-				texture.uav_desc.Texture2DArray.FirstArraySlice = 0;
-				texture.uav_desc.Texture2DArray.ArraySize = 6;
-				texture.uav_desc.Texture2DArray.PlaneSlice = 0;
-			} else if (texture.srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) {
-				texture.srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
-				texture.srv_desc.TextureCubeArray.First2DArrayFace = p_layer;
-				texture.srv_desc.TextureCubeArray.NumCubes = 1;
-				texture.srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f;
-
-				CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
-				texture.uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
-				texture.uav_desc.Texture2DArray.FirstArraySlice = p_layer;
-				texture.uav_desc.Texture2DArray.ArraySize = 6;
-				texture.uav_desc.Texture2DArray.PlaneSlice = 0;
-			} else {
-				CRASH_NOW();
-			}
-		} break;
-		case TEXTURE_SLICE_3D: {
-			CRASH_COND(texture.srv_desc.ViewDimension != D3D12_SRV_DIMENSION_TEXTURE3D);
-			CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE3D);
-			texture.uav_desc.Texture3D.WSize = -1;
-		} break;
-		case TEXTURE_SLICE_2D_ARRAY: {
-			CRASH_COND(texture.srv_desc.ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2DARRAY);
-			texture.srv_desc.Texture2DArray.FirstArraySlice = p_layer;
-			texture.srv_desc.Texture2DArray.ArraySize = slice_layers;
-
-			CRASH_COND(texture.uav_desc.ViewDimension != D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
-			texture.uav_desc.Texture2DArray.FirstArraySlice = p_layer;
-			texture.uav_desc.Texture2DArray.ArraySize = slice_layers;
-		} break;
-	}
-
-	texture.owner = p_with_texture;
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	_add_dependency(id, p_with_texture);
-
-	return id;
-}
-
-Error RenderingDeviceD3D12::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
-	ERR_FAIL_COND_V_MSG((draw_list || compute_list), ERR_INVALID_PARAMETER,
-			"Updating textures is forbidden during creation of a draw or compute list");
-
-	Texture *texture = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);
-
-	if (texture->owner != RID()) {
-		texture = texture_owner.get_or_null(texture->owner);
-		ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.
-	}
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	uint32_t subresource = D3D12CalcSubresource(0, p_layer, 0, texture->mipmaps, texture->layers);
-	_resource_transition_batch(texture, subresource, texture->planes, D3D12_RESOURCE_STATE_COPY_DEST);
-	_resource_transitions_flush(command_list);
-	Error err = _texture_update(texture, p_layer, p_data, p_post_barrier, command_list);
-
-	return err;
-}
-
-static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_dst_pitch, uint32_t p_unit_size) {
-	uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size;
-	uint32_t dst_offset = 0;
-	for (uint32_t y = p_src_h; y > 0; y--) {
-		uint8_t const *__restrict src = p_src + src_offset;
-		uint8_t *__restrict dst = p_dst + dst_offset;
-		for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) {
-			*dst = *src;
-			src++;
-			dst++;
-		}
-		src_offset += p_src_full_w * p_unit_size;
-		dst_offset += p_dst_pitch;
-	}
-}
-
-Error RenderingDeviceD3D12::_texture_update(Texture *p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, ID3D12GraphicsCommandList *p_command_list) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(p_texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
-			"Texture can't be updated while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-
-	ERR_FAIL_COND_V_MSG(!(p_texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
-			"Texture requires the TEXTURE_USAGE_CAN_UPDATE_BIT in order to be updatable.");
-
-	uint32_t layer_count = p_texture->layers;
-	if (p_texture->type == TEXTURE_TYPE_CUBE || p_texture->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		layer_count *= 6;
-	}
-	ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);
-
-	uint32_t width, height;
-	uint32_t image_size = get_image_format_required_size(p_texture->format, p_texture->width, p_texture->height, p_texture->depth, p_texture->mipmaps, &width, &height);
-	uint32_t required_size = image_size;
-	uint32_t required_align = get_compressed_image_format_block_byte_size(p_texture->format);
-	if (required_align == 1) {
-		required_align = get_image_format_pixel_size(p_texture->format);
-	}
-	if ((required_align % 4) != 0) { // Alignment rules are really strange.
-		required_align *= 4;
-	}
-
-	required_align = ALIGN(required_align, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
-
-	ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,
-			"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");
-
-	uint32_t region_size = texture_upload_region_size_px;
-
-	const uint8_t *r = p_data.ptr();
-
-	uint32_t mipmap_offset = 0;
-
-	uint32_t logic_width = p_texture->width;
-	uint32_t logic_height = p_texture->height;
-
-	for (uint32_t mm_i = 0; mm_i < p_texture->mipmaps; mm_i++) {
-		uint32_t depth;
-		uint32_t image_total = get_image_format_required_size(p_texture->format, p_texture->width, p_texture->height, p_texture->depth, mm_i + 1, &width, &height, &depth);
-
-		const uint8_t *read_ptr_mipmap = r + mipmap_offset;
-		image_size = image_total - mipmap_offset;
-
-		UINT dst_subresource = D3D12CalcSubresource(mm_i, p_layer, 0, p_texture->mipmaps, p_texture->layers);
-		CD3DX12_TEXTURE_COPY_LOCATION copy_dst(p_texture->resource, dst_subresource);
-
-		for (uint32_t z = 0; z < depth; z++) { // For 3D textures, depth may be > 0.
-
-			const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth;
-
-			for (uint32_t y = 0; y < height; y += region_size) {
-				for (uint32_t x = 0; x < width; x += region_size) {
-					uint32_t region_w = MIN(region_size, width - x);
-					uint32_t region_h = MIN(region_size, height - y);
-
-					uint32_t pixel_size = get_image_format_pixel_size(p_texture->format);
-					uint32_t block_w, block_h;
-					get_compressed_image_format_block_dimensions(p_texture->format, block_w, block_h);
-
-					uint32_t region_pitch = (region_w * pixel_size * block_w) >> get_compressed_image_format_pixel_rshift(p_texture->format);
-					region_pitch = ALIGN(region_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
-					uint32_t to_allocate = region_pitch * region_h;
-
-					uint32_t alloc_offset, alloc_size;
-					Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false);
-					ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-					uint8_t *write_ptr;
-
-					{ // Map.
-						void *data_ptr = nullptr;
-						HRESULT res = staging_buffer_blocks[staging_buffer_current].resource->Map(0, &VOID_RANGE, &data_ptr);
-						ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "Map failed with error " + vformat("0x%08ux", res) + ".");
-						write_ptr = (uint8_t *)data_ptr;
-						write_ptr += alloc_offset;
-					}
-
-					ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);
-					ERR_FAIL_COND_V(region_pitch % block_w, ERR_BUG);
-					ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);
-
-					if (block_w != 1 || block_h != 1) {
-						// Compressed image (functions).
-						// Must copy a block region.
-
-						uint32_t block_size = get_compressed_image_format_block_byte_size(p_texture->format);
-						// Re-create current variables in blocky format.
-						uint32_t xb = x / block_w;
-						uint32_t yb = y / block_h;
-						uint32_t wb = width / block_w;
-						// Uint32_t hb = height / block_h;.
-						uint32_t region_wb = region_w / block_w;
-						uint32_t region_hb = region_h / block_h;
-						_copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, region_pitch, block_size);
-					} else {
-						// Regular image (pixels).
-						// Must copy a pixel region.
-						_copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, region_pitch, pixel_size);
-					}
-
-					{ // Unmap.
-						staging_buffer_blocks[staging_buffer_current].resource->Unmap(0, &VOID_RANGE);
-					}
-
-					D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = {};
-					src_footprint.Offset = alloc_offset;
-					src_footprint.Footprint = CD3DX12_SUBRESOURCE_FOOTPRINT(
-							d3d12_formats[p_texture->format].family,
-							region_w,
-							region_h,
-							1,
-							region_pitch);
-					CD3DX12_TEXTURE_COPY_LOCATION copy_src(staging_buffer_blocks[staging_buffer_current].resource, src_footprint);
-
-					CD3DX12_BOX src_box(0, 0, region_w, region_h);
-					p_command_list->CopyTextureRegion(&copy_dst, x, y, z, &copy_src, &src_box);
-
-					staging_buffer_blocks.write[staging_buffer_current].fill_amount = alloc_offset + alloc_size;
-				}
-			}
-		}
-
-		mipmap_offset = image_total;
-		logic_width = MAX(1u, logic_width >> 1);
-		logic_height = MAX(1u, logic_height >> 1);
-	}
-
-	return OK;
-}
-
-Vector<uint8_t> RenderingDeviceD3D12::_texture_get_data_from_image(Texture *tex, uint32_t p_layer, bool p_2d) {
-	uint32_t width, height, depth;
-	uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth);
-
-	Vector<uint8_t> image_data;
-	image_data.resize(image_size);
-
-	D3D12_RESOURCE_DESC res_desc = tex->resource->GetDesc();
-
-	uint32_t blockw, blockh;
-	get_compressed_image_format_block_dimensions(tex->format, blockw, blockh);
-	uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format);
-	uint32_t pixel_size = get_image_format_pixel_size(tex->format);
-
-	{
-		uint8_t *w = image_data.ptrw();
-
-		uint32_t mipmap_offset = 0;
-		for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) {
-			uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth);
-
-			uint8_t *write_ptr_mipmap = w + mipmap_offset;
-			image_size = image_total - mipmap_offset;
-
-			UINT subresource = 0;
-
-			uint64_t image_total_src = 0;
-			D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout = {};
-			device->GetCopyableFootprints(
-					&res_desc,
-					subresource,
-					1,
-					0,
-					&layout,
-					nullptr,
-					nullptr,
-					&image_total_src);
-
-			void *img_mem;
-			HRESULT res = tex->resource->Map(subresource, nullptr, &img_mem);
-			ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(), "Map failed with error " + vformat("0x%08ux", res) + ".");
-
-			for (uint32_t z = 0; z < depth; z++) {
-				uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth;
-				const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.Offset + z * image_total_src / depth;
-
-				if (block_size > 1) {
-					// Compressed.
-					uint32_t line_width = (block_size * (width / blockw));
-					for (uint32_t y = 0; y < height / blockh; y++) {
-						const uint8_t *rptr = slice_read_ptr + y * layout.Footprint.RowPitch;
-						uint8_t *wptr = write_ptr + y * line_width;
-
-						memcpy(wptr, rptr, line_width);
-					}
-
-				} else {
-					// Uncompressed.
-					for (uint32_t y = 0; y < height; y++) {
-						const uint8_t *rptr = slice_read_ptr + y * layout.Footprint.RowPitch;
-						uint8_t *wptr = write_ptr + y * pixel_size * width;
-						memcpy(wptr, rptr, (uint64_t)pixel_size * width);
-					}
-				}
-			}
-
-			tex->resource->Unmap(subresource, nullptr);
-
-			mipmap_offset = image_total;
-		}
-	}
-
-	return image_data;
-}
-
-Vector<uint8_t> RenderingDeviceD3D12::texture_get_data(RID p_texture, uint32_t p_layer) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, Vector<uint8_t>());
-
-	ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),
-			"Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-	ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),
-			"Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
-
-	uint32_t layer_count = tex->layers;
-	if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		layer_count *= 6;
-	}
-	ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>());
-
-	if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {
-		// Does not need anything fancy, map and read.
-		return _texture_get_data_from_image(tex, p_layer);
-	} else {
-		// Compute total image size.
-		uint32_t width, height, depth;
-		uint32_t final_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth);
-
-		uint32_t block_w, block_h;
-		get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
-		uint32_t alignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
-
-		// We'll use a potentially bigger buffer to account for mip sizes in which we need to use a bigger pitch to keep D3D12 happy.
-		uint32_t buffer_size = 0;
-		{
-			uint32_t computed_h = tex->height;
-			uint32_t computed_d = tex->depth;
-
-			uint32_t prev_size = 0;
-			for (uint32_t i = 0; i < tex->mipmaps; i++) {
-				uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1);
-				uint32_t inferred_row_pitch = image_size / (computed_h * computed_d) * block_h;
-				uint32_t adjusted_row_pitch = ALIGN(inferred_row_pitch, alignment);
-				uint32_t adjusted_image_size = adjusted_row_pitch / block_h * computed_h * tex->depth;
-				uint32_t size = adjusted_image_size - prev_size;
-				prev_size = image_size;
-
-				buffer_size = ALIGN(buffer_size + size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
-
-				computed_h = MAX(1u, computed_h >> 1);
-				computed_d = MAX(1u, computed_d >> 1);
-			}
-		}
-
-		// Allocate buffer.
-		ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get(); // Makes more sense to retrieve.
-
-		Buffer tmp_buffer;
-		Error err = _buffer_allocate(&tmp_buffer, buffer_size, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_HEAP_TYPE_READBACK);
-		ERR_FAIL_COND_V(err != OK, Vector<uint8_t>());
-
-		for (uint32_t i = 0; i < tex->mipmaps; i++) {
-			uint32_t subresource = D3D12CalcSubresource(i, p_layer, 0, tex->owner_mipmaps, tex->owner_layers);
-			_resource_transition_batch(tex, subresource, tex->planes, D3D12_RESOURCE_STATE_COPY_SOURCE);
-		}
-		_resource_transitions_flush(command_list);
-
-		uint32_t computed_w = tex->width;
-		uint32_t computed_h = tex->height;
-		uint32_t computed_d = tex->depth;
-
-		uint32_t prev_size = 0;
-		uint32_t offset = 0;
-		for (uint32_t i = 0; i < tex->mipmaps; i++) {
-			uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1);
-			uint32_t size = image_size - prev_size;
-			prev_size = image_size;
-
-			D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = {};
-			dst_footprint.Offset = offset;
-			dst_footprint.Footprint.Width = MAX(block_w, computed_w);
-			dst_footprint.Footprint.Height = MAX(block_h, computed_h);
-			dst_footprint.Footprint.Depth = computed_d;
-			uint32_t inferred_row_pitch = size / (dst_footprint.Footprint.Height * computed_d) * block_h;
-			dst_footprint.Footprint.RowPitch = inferred_row_pitch;
-			dst_footprint.Footprint.Format = d3d12_formats[tex->format].family;
-			CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tmp_buffer.resource, dst_footprint);
-
-			UINT src_subresource = D3D12CalcSubresource(i, p_layer, 0, tex->owner_mipmaps, tex->owner_layers);
-			CD3DX12_TEXTURE_COPY_LOCATION copy_src(tex->resource, src_subresource);
-
-			if (dst_footprint.Footprint.RowPitch % alignment) {
-				// Dammit! Now we must copy with an imposed pitch and then adjust row by row.
-				copy_dst.PlacedFootprint.Offset = ALIGN(offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
-
-				uint32_t adjusted_row_pitch = ALIGN(inferred_row_pitch, alignment);
-				copy_dst.PlacedFootprint.Footprint.RowPitch = adjusted_row_pitch;
-				command_list->CopyTextureRegion(&copy_dst, 0, 0, 0, &copy_src, nullptr);
-				_flush(true);
-
-				void *buffer_mem;
-				uint32_t adjusted_size = adjusted_row_pitch / block_h * dst_footprint.Footprint.Height * computed_d;
-				CD3DX12_RANGE range(offset, copy_dst.PlacedFootprint.Offset + adjusted_size);
-				HRESULT res = tmp_buffer.resource->Map(0, &range, &buffer_mem);
-				ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(), "Map failed with error " + vformat("0x%08ux", res) + ".");
-
-				for (uint32_t j = 0; j < dst_footprint.Footprint.Height / block_h * computed_d; j++) {
-					memmove((uint8_t *)buffer_mem + offset + j * inferred_row_pitch, (uint8_t *)buffer_mem + copy_dst.PlacedFootprint.Offset + j * adjusted_row_pitch, inferred_row_pitch);
-				}
-
-				tmp_buffer.resource->Unmap(0, nullptr);
-			} else if (offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) {
-				// Row pitch is fine, but offset alignment is not good.
-				copy_dst.PlacedFootprint.Offset = ALIGN(offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
-
-				command_list->CopyTextureRegion(&copy_dst, 0, 0, 0, &copy_src, nullptr);
-				_flush(true);
-
-				void *buffer_mem;
-				CD3DX12_RANGE range(copy_dst.PlacedFootprint.Offset, size);
-				HRESULT res = tmp_buffer.resource->Map(0, &range, &buffer_mem);
-				ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(), "Map failed with error " + vformat("0x%08ux", res) + ".");
-
-				memmove((uint8_t *)buffer_mem + offset, (uint8_t *)buffer_mem + copy_dst.PlacedFootprint.Offset, size);
-
-				tmp_buffer.resource->Unmap(0, nullptr);
-			} else {
-				command_list->CopyTextureRegion(&copy_dst, 0, 0, 0, &copy_src, nullptr);
-			}
-
-			computed_w = MAX(1u, computed_w >> 1);
-			computed_h = MAX(1u, computed_h >> 1);
-			computed_d = MAX(1u, computed_d >> 1);
-			offset += size;
-		}
-
-		_flush(true);
-
-		void *buffer_mem;
-		CD3DX12_RANGE range(0, final_buffer_size);
-		HRESULT res = tmp_buffer.resource->Map(0, &range, &buffer_mem);
-		ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(), "Map failed with error " + vformat("0x%08ux", res) + ".");
-
-		Vector<uint8_t> buffer_data;
-		buffer_data.resize(final_buffer_size);
-		{
-			uint8_t *w = buffer_data.ptrw();
-			memcpy(w, buffer_mem, final_buffer_size);
-		}
-
-		tmp_buffer.resource->Unmap(0, nullptr);
-
-		_buffer_free(&tmp_buffer);
-
-		return buffer_data;
-	}
-}
-
-bool RenderingDeviceD3D12::texture_is_shared(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, false);
-	return tex->owner.is_valid();
-}
-
-bool RenderingDeviceD3D12::texture_is_valid(RID p_texture) {
-	return texture_owner.owns(p_texture);
-}
-
-RenderingDevice::TextureFormat RenderingDeviceD3D12::texture_get_format(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, TextureFormat());
-
-	TextureFormat tf;
-
-	tf.format = tex->format;
-	tf.width = tex->width;
-	tf.height = tex->height;
-	tf.depth = tex->depth;
-	tf.array_layers = tex->layers;
-	tf.mipmaps = tex->mipmaps;
-	tf.texture_type = tex->type;
-	tf.samples = tex->samples;
-	tf.usage_bits = tex->usage_flags;
-	tf.shareable_formats = tex->allowed_shared_formats;
-	tf.is_resolve_buffer = tex->is_resolve_buffer;
-
-	return tf;
-}
-
-Size2i RenderingDeviceD3D12::texture_size(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, Size2i());
-	return Size2i(tex->width, tex->height);
-}
-
-uint64_t RenderingDeviceD3D12::texture_get_native_handle(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, 0);
-
-	return (uint64_t)tex->resource;
-}
-
-Error RenderingDeviceD3D12::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_from_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
-
-	uint32_t src_layer_count = src_tex->layers;
-	uint32_t src_width, src_height, src_depth;
-	get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth);
-	if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		src_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER);
-
-	Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
-	ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
-			"Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-	ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved.");
-
-	uint32_t dst_layer_count = dst_tex->layers;
-	uint32_t dst_width, dst_height, dst_depth;
-	get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth);
-	if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		dst_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG((src_tex->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != (dst_tex->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), ERR_INVALID_PARAMETER,
-			"Source and destination texture must be of the same type (color or depth).");
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	uint32_t src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex->owner_mipmaps, src_tex->owner_layers);
-	_resource_transition_batch(src_tex, src_subresource, src_tex->planes, D3D12_RESOURCE_STATE_COPY_SOURCE);
-
-	uint32_t dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex->owner_mipmaps, dst_tex->owner_layers);
-	_resource_transition_batch(dst_tex, dst_subresource, dst_tex->planes, D3D12_RESOURCE_STATE_COPY_DEST);
-
-	_resource_transitions_flush(command_list);
-
-	{
-		CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex->resource, src_subresource);
-		CD3DX12_BOX src_box(p_from.x, p_from.y, p_from.z, p_from.x + p_size.x, p_from.y + p_size.y, p_from.z + p_size.z);
-		CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex->resource, dst_subresource);
-		command_list->CopyTextureRegion(
-				&dst_location,
-				p_to.x, p_to.y, p_to.z,
-				&src_location,
-				&src_box);
-	}
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_from_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
-
-	ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)");
-	ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");
-
-	Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
-	ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
-			"Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-	ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved.");
-
-	ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture).");
-	ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");
-
-	ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format.");
-	ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destination textures must have the same dimensions.");
-
-	ERR_FAIL_COND_V_MSG((src_tex->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != (dst_tex->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), ERR_INVALID_PARAMETER,
-			"Source and destination texture must be of the same type (color or depth).");
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	uint32_t src_subresource = D3D12CalcSubresource(src_tex->base_mipmap, src_tex->base_layer, 0, src_tex->owner_mipmaps, src_tex->owner_layers);
-	_resource_transition_batch(src_tex, src_subresource, src_tex->planes, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
-
-	uint32_t dst_subresource = D3D12CalcSubresource(dst_tex->base_mipmap, dst_tex->base_layer, 0, dst_tex->owner_mipmaps, dst_tex->owner_layers);
-	_resource_transition_batch(dst_tex, dst_subresource, dst_tex->planes, D3D12_RESOURCE_STATE_RESOLVE_DEST);
-
-	_resource_transitions_flush(command_list);
-
-	command_list->ResolveSubresource(dst_tex->resource, dst_subresource, src_tex->resource, src_subresource, d3d12_formats[src_tex->format].general_format);
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be cleared while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
-
-	ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be cleared.");
-
-	uint32_t src_layer_count = src_tex->layers;
-	if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		src_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER);
-
-	if ((src_tex->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-		// Clear via RTV.
-
-		if (frames[frame].desc_heap_walkers.rtv.is_at_eof()) {
-			if (!frames[frame].desc_heaps_exhausted_reported.rtv) {
-				frames[frame].desc_heaps_exhausted_reported.rtv = true;
-				ERR_FAIL_V_MSG(ERR_BUSY,
-						"Cannot clear texture because there's no enough room in current frame's RENDER TARGET descriptors heap.\n"
-						"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
-			} else {
-				return ERR_BUSY;
-			}
-		}
-
-		D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(src_tex, p_base_mipmap, p_base_layer, p_layers);
-		rtv_desc.Format = src_tex->owner_uav_desc.Format;
-
-		ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-		for (uint32_t i = 0; i < p_layers; i++) {
-			for (uint32_t j = 0; j < p_mipmaps; j++) {
-				uint32_t subresource = D3D12CalcSubresource(src_tex->base_mipmap + p_base_mipmap + j, src_tex->base_layer + p_base_layer + i, 0, src_tex->owner_mipmaps, src_tex->owner_layers);
-				_resource_transition_batch(src_tex, subresource, src_tex->planes, D3D12_RESOURCE_STATE_RENDER_TARGET, src_tex->owner_resource);
-			}
-		}
-		_resource_transitions_flush(command_list);
-
-		device->CreateRenderTargetView(
-				src_tex->owner_resource,
-				&rtv_desc,
-				frames[frame].desc_heap_walkers.rtv.get_curr_cpu_handle());
-		command_list->ClearRenderTargetView(
-				frames[frame].desc_heap_walkers.rtv.get_curr_cpu_handle(),
-				p_color.components,
-				0,
-				nullptr);
-		frames[frame].desc_heap_walkers.rtv.advance();
-	} else {
-		// Clear via UAV.
-
-		if (frames[frame].desc_heap_walkers.resources.is_at_eof()) {
-			if (!frames[frame].desc_heaps_exhausted_reported.resources) {
-				frames[frame].desc_heaps_exhausted_reported.resources = true;
-				ERR_FAIL_V_MSG(ERR_BUSY,
-						"Cannot clear texture because there's no enough room in current frame's RESOURCE descriptors heap.\n"
-						"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
-			} else {
-				return ERR_BUSY;
-			}
-		}
-		if (frames[frame].desc_heap_walkers.aux.is_at_eof()) {
-			if (!frames[frame].desc_heaps_exhausted_reported.aux) {
-				frames[frame].desc_heaps_exhausted_reported.aux = true;
-				ERR_FAIL_V_MSG(ERR_BUSY,
-						"Cannot clear texture because there's no enough room in current frame's AUX descriptors heap.\n"
-						"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
-			} else {
-				return ERR_BUSY;
-			}
-		}
-
-		ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-		for (uint32_t i = 0; i < p_layers; i++) {
-			for (uint32_t j = 0; j < p_mipmaps; j++) {
-				uint32_t subresource = D3D12CalcSubresource(src_tex->base_mipmap + p_base_mipmap + j, src_tex->base_layer + p_base_layer + i, 0, src_tex->owner_mipmaps, src_tex->owner_layers);
-				_resource_transition_batch(src_tex, subresource, src_tex->planes, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, src_tex->owner_resource);
-			}
-		}
-		_resource_transitions_flush(command_list);
-
-		device->CreateUnorderedAccessView(
-				src_tex->owner_resource,
-				nullptr,
-				&src_tex->owner_uav_desc,
-				frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle());
-
-		device->CopyDescriptorsSimple(
-				1,
-				frames[frame].desc_heap_walkers.resources.get_curr_cpu_handle(),
-				frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle(),
-				D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
-
-		UINT values[4] = {
-			(UINT)p_color.get_r8(),
-			(UINT)p_color.get_g8(),
-			(UINT)p_color.get_b8(),
-			(UINT)p_color.get_a8(),
-		};
-		command_list->ClearUnorderedAccessViewUint(
-				frames[frame].desc_heap_walkers.resources.get_curr_gpu_handle(),
-				frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle(),
-				src_tex->owner_resource,
-				values,
-				0,
-				nullptr);
-
-		frames[frame].desc_heap_walkers.resources.advance();
-		frames[frame].desc_heap_walkers.aux.advance();
-	}
-
-	return OK;
-}
-
-bool RenderingDeviceD3D12::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const {
-	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
-
-	_THREAD_SAFE_METHOD_
-
-	D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
-	srv_rtv_support.Format = d3d12_formats[p_format].general_format;
-	HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
-	ERR_FAIL_COND_V_MSG(res, false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
-
-	D3D12_FEATURE_DATA_FORMAT_SUPPORT &uav_support = srv_rtv_support; // Fine for now.
-
-	D3D12_FEATURE_DATA_FORMAT_SUPPORT dsv_support = {};
-	dsv_support.Format = d3d12_formats[p_format].dsv_format;
-	res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dsv_support, sizeof(dsv_support));
-	ERR_FAIL_COND_V_MSG(res, false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
-
-	if ((p_usage & TEXTURE_USAGE_SAMPLING_BIT) && !(srv_rtv_support.Support1 & (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) && d3d12_formats[p_format].general_format != DXGI_FORMAT_UNKNOWN) {
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_SAMPLING_BIT) && d3d12_formats[p_format].general_format == DXGI_FORMAT_UNKNOWN) {
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(dsv_support.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {
-		printf("dxgiformat: %x\n", d3d12_formats[p_format].dsv_format);
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_STORAGE_BIT) && !(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { // Maybe check LOAD/STORE, too?
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !(uav_support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD)) { // Check a basic atomic at least.
-		return false;
-	}
-
-	if ((p_usage & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && d3d12_formats[p_format].general_format != DXGI_FORMAT_R8_UINT) {
-		return false;
-	}
-
-	return true;
-}
-
-/********************/
-/**** ATTACHMENT ****/
-/********************/
-
-bool RenderingDeviceD3D12::_framebuffer_format_preprocess(FramebufferFormat *p_fb_format, uint32_t p_view_count) {
-	const Vector<AttachmentFormat> &attachments = p_fb_format->attachments;
-
-	LocalVector<int32_t> attachment_last_pass;
-	attachment_last_pass.resize(attachments.size());
-
-	if (p_view_count > 1) {
-		const D3D12Context::MultiviewCapabilities &capabilities = context->get_multiview_capabilities();
-
-		// This only works with multiview!
-		ERR_FAIL_COND_V_MSG(!capabilities.is_supported, false, "Multiview not supported");
-
-		// Make sure we limit this to the number of views we support.
-		ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, false, "Hardware does not support requested number of views for Multiview render pass");
-	}
-
-	int attachment_count = 0;
-	HashSet<DXGI_FORMAT> ms_attachment_formats;
-	for (int i = 0; i < attachments.size(); i++) {
-		if (attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {
-			continue;
-		}
-
-		ERR_FAIL_INDEX_V(attachments[i].format, DATA_FORMAT_MAX, false);
-		ERR_FAIL_INDEX_V(attachments[i].samples, TEXTURE_SAMPLES_MAX, false);
-		ERR_FAIL_COND_V_MSG(!(attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)),
-				ERR_INVALID_PARAMETER, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");
-
-		attachment_last_pass[i] = -1;
-		attachment_count++;
-
-		if (attachments[i].samples != TEXTURE_SAMPLES_1) {
-			if ((attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-				ms_attachment_formats.insert(d3d12_formats[attachments[i].format].general_format);
-			} else if ((attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-				ms_attachment_formats.insert(d3d12_formats[attachments[i].format].dsv_format);
-			}
-		}
-	}
-
-	Vector<FramebufferPass> &passes = p_fb_format->passes;
-	for (int i = 0; i < passes.size(); i++) {
-		FramebufferPass *pass = &passes.write[i];
-
-		TextureSamples texture_samples = TEXTURE_SAMPLES_1;
-		bool is_multisample_first = true;
-
-		ERR_FAIL_COND_V(pass->color_attachments.size() > D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT, false);
-		for (int j = 0; j < pass->color_attachments.size(); j++) {
-			int32_t attachment = pass->color_attachments[j];
-			if (attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-				ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(!(attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as color attachment.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-
-				if (is_multisample_first) {
-					texture_samples = attachments[attachment].samples;
-					is_multisample_first = false;
-				} else {
-					ERR_FAIL_COND_V_MSG(texture_samples != attachments[attachment].samples, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples.");
-				}
-				attachment_last_pass[attachment] = i;
-			}
-		}
-
-		for (int j = 0; j < pass->input_attachments.size(); j++) {
-			int32_t attachment = pass->input_attachments[j];
-			if (attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-				ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(!(attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-
-				if ((attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-					ERR_FAIL_V_MSG(false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), the D3D12 driver doesn't yet support using depth-stencil targets as input attachments.");
-				}
-
-				attachment_last_pass[attachment] = i;
-			}
-		}
-
-		if (pass->resolve_attachments.size() > 0) {
-			ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), false, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ").");
-			ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, false, "Resolve attachments specified, but color attachments are not multisample.");
-		}
-		for (int j = 0; j < pass->resolve_attachments.size(); j++) {
-			int32_t attachment = pass->resolve_attachments[j];
-			if (attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-				ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused.");
-				ERR_FAIL_COND_V_MSG(!(attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-				bool multisample = attachments[attachment].samples > TEXTURE_SAMPLES_1;
-				ERR_FAIL_COND_V_MSG(multisample, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
-				attachment_last_pass[attachment] = i;
-			}
-		}
-
-		if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-			int32_t attachment = pass->depth_attachment;
-			ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");
-			ERR_FAIL_COND_V_MSG(!(attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), false, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment.");
-			ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, false, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-			attachment_last_pass[attachment] = i;
-
-			if (is_multisample_first) {
-				texture_samples = attachments[attachment].samples;
-				is_multisample_first = false;
-			} else {
-				ERR_FAIL_COND_V_MSG(texture_samples != attachments[attachment].samples, false, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth.");
-			}
-		}
-
-		if (context->get_vrs_capabilities().ss_image_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-			int32_t attachment = pass->vrs_attachment;
-			ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment.");
-			ERR_FAIL_COND_V_MSG(!(attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), false, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment.");
-			ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, false, "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-			attachment_last_pass[attachment] = i;
-		}
-
-		for (int j = 0; j < pass->preserve_attachments.size(); j++) {
-			int32_t attachment = pass->preserve_attachments[j];
-
-			ERR_FAIL_COND_V_MSG(attachment == FramebufferPass::ATTACHMENT_UNUSED, false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + "). Preserve attachments can't be unused.");
-
-			ERR_FAIL_INDEX_V_MSG(attachment, attachments.size(), false, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");
-
-			if (attachment_last_pass[attachment] != i) {
-				// Preserve can still be used to keep depth or color from being discarded after use.
-				attachment_last_pass[attachment] = i;
-			}
-		}
-
-		p_fb_format->pass_samples.push_back(texture_samples);
-	}
-
-	if (p_fb_format->view_count > 1) {
-		const D3D12Context::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
-
-		// For now this only works with multiview!
-		ERR_FAIL_COND_V_MSG(!capabilities.is_supported, ERR_UNAVAILABLE, "Multiview not supported");
-
-		// Make sure we limit this to the number of views we support.
-		ERR_FAIL_COND_V_MSG(p_fb_format->view_count > capabilities.max_view_count, ERR_UNAVAILABLE, "Hardware does not support requested number of views for Multiview render pass");
-	}
-
-	if (!ms_attachment_formats.is_empty()) {
-		LocalVector<DXGI_FORMAT> formats;
-		for (DXGI_FORMAT f : ms_attachment_formats) {
-			formats.push_back(f);
-		}
-		p_fb_format->max_supported_sample_count = _find_max_common_supported_sample_count(formats.ptr(), formats.size());
-	}
-
-	return true;
-}
-
-uint32_t RenderingDeviceD3D12::_find_max_common_supported_sample_count(const DXGI_FORMAT *p_formats, uint32_t p_num_formats) {
-	uint32_t common = UINT32_MAX;
-
-	for (uint32_t i = 0; i < p_num_formats; i++) {
-		if (format_sample_counts_mask_cache.has(p_formats[i])) {
-			common &= format_sample_counts_mask_cache[p_formats[i]];
-		} else {
-			D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msql = {};
-			msql.Format = p_formats[i];
-			uint32_t mask = 0;
-			for (int samples = 1 << (TEXTURE_SAMPLES_MAX - 1); samples >= 1; samples /= 2) {
-				msql.SampleCount = (UINT)samples;
-				HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msql, sizeof(msql));
-				if (SUCCEEDED(res) && msql.NumQualityLevels) {
-					int bit = get_shift_from_power_of_2(samples);
-					ERR_FAIL_COND_V(bit == -1, 1);
-					mask |= (uint32_t)(1 << bit);
-				}
-			}
-			format_sample_counts_mask_cache.insert(p_formats[i], mask);
-			common &= mask;
-		}
-	}
-	if (common == UINT32_MAX) {
-		return 1;
-	} else {
-		return (uint32_t)1 << nearest_shift(common);
-	}
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceD3D12::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) {
-	FramebufferPass pass;
-	for (int i = 0; i < p_format.size(); i++) {
-		if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-			pass.depth_attachment = i;
-		} else {
-			pass.color_attachments.push_back(i);
-		}
-	}
-
-	Vector<FramebufferPass> passes;
-	passes.push_back(pass);
-	return framebuffer_format_create_multipass(p_format, passes, p_view_count);
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceD3D12::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	FramebufferFormat fb_format;
-	fb_format.attachments = p_attachments;
-	fb_format.passes = p_passes;
-	fb_format.view_count = p_view_count;
-	if (!_framebuffer_format_preprocess(&fb_format, p_view_count)) {
-		return INVALID_ID;
-	}
-
-	FramebufferFormatID id = FramebufferFormatID(framebuffer_formats.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));
-	framebuffer_formats[id] = fb_format;
-	return id;
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceD3D12::framebuffer_format_create_empty(TextureSamples p_samples) {
-	_THREAD_SAFE_METHOD_
-
-	FramebufferFormat fb_format;
-	fb_format.passes.push_back(FramebufferPass());
-	fb_format.pass_samples.push_back(p_samples);
-
-	FramebufferFormatID id = FramebufferFormatID(framebuffer_formats.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));
-	framebuffer_formats[id] = fb_format;
-	return id;
-}
-
-RenderingDevice::TextureSamples RenderingDeviceD3D12::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) {
-	HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format);
-	ERR_FAIL_NULL_V(E, TEXTURE_SAMPLES_1);
-	ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1);
-
-	return E->value.pass_samples[p_pass];
-}
-
-/***********************/
-/**** RENDER TARGET ****/
-/***********************/
-
-RID RenderingDeviceD3D12::framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples, FramebufferFormatID p_format_check) {
-	_THREAD_SAFE_METHOD_
-	Framebuffer framebuffer;
-	framebuffer.format_id = framebuffer_format_create_empty(p_samples);
-	ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());
-	framebuffer.size = p_size;
-
-	return framebuffer_owner.make_rid(framebuffer);
-}
-
-RID RenderingDeviceD3D12::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	FramebufferPass pass;
-
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
-
-		ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
-
-		if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-			pass.depth_attachment = i;
-		} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
-			pass.vrs_attachment = i;
-		} else {
-			if (texture && texture->is_resolve_buffer) {
-				pass.resolve_attachments.push_back(i);
-			} else {
-				pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
-			}
-		}
-	}
-
-	Vector<FramebufferPass> passes;
-	passes.push_back(pass);
-
-	return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);
-}
-
-D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceD3D12::_make_rtv_for_texture(const RenderingDeviceD3D12::Texture *p_texture, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers) {
-	D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {};
-	rtv_desc.Format = p_texture->srv_desc.Format;
-
-	switch (p_texture->srv_desc.ViewDimension) {
-		case D3D12_SRV_DIMENSION_TEXTURE1D: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
-			rtv_desc.Texture1D.MipSlice = p_texture->srv_desc.Texture1D.MostDetailedMip + p_mipmap_offset;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
-			rtv_desc.Texture1DArray.MipSlice = p_texture->srv_desc.Texture1DArray.MostDetailedMip + p_mipmap_offset;
-			rtv_desc.Texture1DArray.FirstArraySlice = p_texture->srv_desc.Texture1DArray.FirstArraySlice + p_layer_offset;
-			rtv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture->srv_desc.Texture1DArray.ArraySize : p_layers;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2D: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
-			rtv_desc.Texture2D.MipSlice = p_texture->srv_desc.Texture2D.MostDetailedMip + p_mipmap_offset;
-			rtv_desc.Texture2D.PlaneSlice = p_texture->srv_desc.Texture2D.PlaneSlice;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
-			rtv_desc.Texture2DArray.MipSlice = p_texture->srv_desc.Texture2DArray.MostDetailedMip + p_mipmap_offset;
-			rtv_desc.Texture2DArray.FirstArraySlice = p_texture->srv_desc.Texture2DArray.FirstArraySlice + p_layer_offset;
-			rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture->srv_desc.Texture2DArray.ArraySize : p_layers;
-			rtv_desc.Texture2DArray.PlaneSlice = p_texture->srv_desc.Texture2DArray.PlaneSlice;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
-			rtv_desc.Texture2DMSArray.FirstArraySlice = p_texture->srv_desc.Texture2DMSArray.FirstArraySlice + p_layer_offset;
-			rtv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture->srv_desc.Texture2DMSArray.ArraySize : p_layers;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE3D: {
-			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
-			rtv_desc.Texture3D.MipSlice = p_texture->srv_desc.Texture3D.MostDetailedMip + p_mipmap_offset;
-			rtv_desc.Texture3D.FirstWSlice = 0;
-			rtv_desc.Texture3D.WSize = p_texture->depth;
-		} break;
-		default: {
-			ERR_FAIL_V_MSG(D3D12_RENDER_TARGET_VIEW_DESC(), "Can't create an RTV from an SRV whose view dimension is " + itos(p_texture->srv_desc.ViewDimension) + ".");
-		}
-	}
-
-	return rtv_desc;
-}
-
-D3D12_DEPTH_STENCIL_VIEW_DESC RenderingDeviceD3D12::_make_dsv_for_texture(const RenderingDeviceD3D12::Texture *p_texture) {
-	D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
-	dsv_desc.Format = d3d12_formats[p_texture->format].dsv_format;
-	dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
-
-	switch (p_texture->srv_desc.ViewDimension) {
-		case D3D12_SRV_DIMENSION_TEXTURE1D: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D;
-			dsv_desc.Texture1D.MipSlice = p_texture->srv_desc.Texture1D.MostDetailedMip;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
-			dsv_desc.Texture1DArray.MipSlice = p_texture->srv_desc.Texture1DArray.MostDetailedMip;
-			dsv_desc.Texture1DArray.FirstArraySlice = p_texture->srv_desc.Texture1DArray.FirstArraySlice;
-			dsv_desc.Texture1DArray.ArraySize = p_texture->srv_desc.Texture1DArray.ArraySize;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2D: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
-			dsv_desc.Texture2D.MipSlice = p_texture->srv_desc.Texture2D.MostDetailedMip;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
-			dsv_desc.Texture2DArray.MipSlice = p_texture->srv_desc.Texture2DArray.MostDetailedMip;
-			dsv_desc.Texture2DArray.FirstArraySlice = p_texture->srv_desc.Texture2DArray.FirstArraySlice;
-			dsv_desc.Texture2DArray.ArraySize = p_texture->srv_desc.Texture2DArray.ArraySize;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
-			dsv_desc.Texture2DMS.UnusedField_NothingToDefine = p_texture->srv_desc.Texture2DMS.UnusedField_NothingToDefine;
-		} break;
-		case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
-			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
-			dsv_desc.Texture2DMSArray.FirstArraySlice = p_texture->srv_desc.Texture2DMSArray.FirstArraySlice;
-			dsv_desc.Texture2DMSArray.ArraySize = p_texture->srv_desc.Texture2DMSArray.ArraySize;
-		} break;
-		default: {
-			ERR_FAIL_V_MSG(D3D12_DEPTH_STENCIL_VIEW_DESC(), "Can't create an RTV from an SRV whose view dimension is " + itos(p_texture->srv_desc.ViewDimension) + ".");
-		}
-	}
-
-	return dsv_desc;
-}
-
-RID RenderingDeviceD3D12::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	Vector<AttachmentFormat> attachments;
-	attachments.resize(p_texture_attachments.size());
-	Vector<uint32_t> attachments_handle_inds;
-	attachments_handle_inds.resize(p_texture_attachments.size());
-	Size2i size;
-	bool size_set = false;
-	int num_color = 0;
-	int num_depth = 0;
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		AttachmentFormat af;
-		Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
-		if (!texture) {
-			af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;
-			attachments_handle_inds.write[i] = UINT32_MAX;
-		} else {
-			ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
-
-			if (!size_set) {
-				size.width = texture->width;
-				size.height = texture->height;
-				size_set = true;
-			} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
-				// If this is not the first attachment we assume this is used as the VRS attachment.
-				// In this case this texture will be 1/16th the size of the color attachment.
-				// So we skip the size check.
-			} else {
-				ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
-						"All textures in a framebuffer should be the same size.");
-			}
-
-			af.format = texture->format;
-			af.samples = texture->samples;
-			af.usage_flags = texture->usage_flags;
-
-			bool is_vrs = texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
-			if (is_vrs) {
-			} else if ((texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-				attachments_handle_inds.write[i] = num_color;
-				num_color++;
-			} else if ((texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-				attachments_handle_inds.write[i] = num_depth;
-				num_depth++;
-			} else {
-				attachments_handle_inds.write[i] = UINT32_MAX;
-			}
-		}
-		attachments.write[i] = af;
-	}
-
-	ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");
-
-	FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count);
-	if (format_id == INVALID_ID) {
-		return RID();
-	}
-
-	ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(),
-			"The format used to check this framebuffer differs from the intended framebuffer format.");
-
-	Framebuffer framebuffer;
-	framebuffer.format_id = format_id;
-	framebuffer.texture_ids = p_texture_attachments;
-	framebuffer.attachments_handle_inds = attachments_handle_inds;
-	framebuffer.size = size;
-	framebuffer.view_count = p_view_count;
-
-	{
-		if (num_color) {
-			Error err = framebuffer.rtv_heap.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, num_color, false);
-			ERR_FAIL_COND_V(err, RID());
-		}
-		DescriptorsHeap::Walker rtv_heap_walker = framebuffer.rtv_heap.make_walker();
-
-		if (num_depth) {
-			Error err = framebuffer.dsv_heap.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, num_depth, false);
-			ERR_FAIL_COND_V(err, RID());
-		}
-		DescriptorsHeap::Walker dsv_heap_walker = framebuffer.dsv_heap.make_walker();
-
-		for (int i = 0; i < p_texture_attachments.size(); i++) {
-			Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
-			if (!texture) {
-				continue;
-			}
-
-			bool is_vrs = texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
-			if (is_vrs) {
-			} else if ((texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-				D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(texture);
-				device->CreateRenderTargetView(texture->resource, &rtv_desc, rtv_heap_walker.get_curr_cpu_handle());
-				rtv_heap_walker.advance();
-			} else if ((texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-				D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(texture);
-				device->CreateDepthStencilView(texture->resource, &dsv_desc, dsv_heap_walker.get_curr_cpu_handle());
-				dsv_heap_walker.advance();
-			}
-		}
-
-		DEV_ASSERT(rtv_heap_walker.is_at_eof());
-		DEV_ASSERT(dsv_heap_walker.is_at_eof());
-	}
-
-	RID id = framebuffer_owner.make_rid(framebuffer);
-
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		if (p_texture_attachments[i].is_valid()) {
-			_add_dependency(id, p_texture_attachments[i]);
-		}
-	}
-
-	return id;
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceD3D12::framebuffer_get_format(RID p_framebuffer) {
-	_THREAD_SAFE_METHOD_
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
-
-	return framebuffer->format_id;
-}
-
-bool RenderingDeviceD3D12::framebuffer_is_valid(RID p_framebuffer) const {
-	_THREAD_SAFE_METHOD_
-
-	return framebuffer_owner.owns(p_framebuffer);
-}
-
-void RenderingDeviceD3D12::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {
-	_THREAD_SAFE_METHOD_
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL(framebuffer);
-
-	framebuffer->invalidated_callback = p_callback;
-	framebuffer->invalidated_callback_userdata = p_userdata;
-}
-
-/*****************/
-/**** SAMPLER ****/
-/*****************/
-
-RID RenderingDeviceD3D12::sampler_create(const SamplerState &p_state) {
-	_THREAD_SAFE_METHOD_
-
-	D3D12_SAMPLER_DESC sampler_desc = {};
-
-	if (p_state.use_anisotropy) {
-		sampler_desc.Filter = D3D12_ENCODE_ANISOTROPIC_FILTER(D3D12_FILTER_REDUCTION_TYPE_STANDARD);
-		sampler_desc.MaxAnisotropy = p_state.anisotropy_max;
-	} else {
-		static const D3D12_FILTER_TYPE d3d12_filter_types[] = {
-			D3D12_FILTER_TYPE_POINT, // SAMPLER_FILTER_NEAREST.
-			D3D12_FILTER_TYPE_LINEAR, // SAMPLER_FILTER_LINEAR.
-		};
-		sampler_desc.Filter = D3D12_ENCODE_BASIC_FILTER(
-				d3d12_filter_types[p_state.min_filter],
-				d3d12_filter_types[p_state.mag_filter],
-				d3d12_filter_types[p_state.mip_filter],
-				p_state.enable_compare ? D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD);
-	}
-
-	ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_desc.AddressU = address_modes[p_state.repeat_u];
-	ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_desc.AddressV = address_modes[p_state.repeat_v];
-	ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_desc.AddressW = address_modes[p_state.repeat_w];
-
-	ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID());
-	for (int i = 0; i < 4; i++) {
-		sampler_desc.BorderColor[i] = sampler_border_colors[p_state.border_color][i];
-	}
-
-	sampler_desc.MinLOD = p_state.min_lod;
-	sampler_desc.MaxLOD = p_state.max_lod;
-	sampler_desc.MipLODBias = p_state.lod_bias;
-
-	ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID());
-	sampler_desc.ComparisonFunc = p_state.enable_compare ? compare_operators[p_state.compare_op] : D3D12_COMPARISON_FUNC_NEVER;
-
-	// TODO: Emulate somehow?
-	if (p_state.unnormalized_uvw) {
-		WARN_PRINT("Creating a sampler with unnormalized UVW, which is not supported.");
-	}
-
-	return sampler_owner.make_rid(sampler_desc);
-}
-
-bool RenderingDeviceD3D12::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {
-	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
-
-	_THREAD_SAFE_METHOD_
-
-	D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
-	srv_rtv_support.Format = d3d12_formats[p_format].general_format;
-	HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
-	ERR_FAIL_COND_V_MSG(res, false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", res) + ".");
-
-	return (srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE);
-}
-
-/**********************/
-/**** VERTEX ARRAY ****/
-/**********************/
-
-RID RenderingDeviceD3D12::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, bool p_use_as_storage) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	Buffer buffer;
-	D3D12_RESOURCE_STATES usage = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
-	if (p_use_as_storage) {
-		usage |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-	}
-	Error err = _buffer_allocate(&buffer, p_size_bytes, usage, D3D12_HEAP_TYPE_DEFAULT);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-	}
-
-	RID id = vertex_buffer_owner.make_rid(buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
-RenderingDevice::VertexFormatID RenderingDeviceD3D12::vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) {
-	_THREAD_SAFE_METHOD_
-
-	VertexDescriptionKey key;
-	key.vertex_formats = p_vertex_formats;
-
-	VertexFormatID *idptr = vertex_format_cache.getptr(key);
-	if (idptr) {
-		return *idptr;
-	}
-
-	// Does not exist, create one and cache it.
-	VertexDescriptionCache vdcache;
-	vdcache.elements_desc.resize(p_vertex_formats.size());
-
-	HashSet<int> used_locations;
-	for (int i = 0; i < p_vertex_formats.size(); i++) {
-		ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX);
-		ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID);
-
-		ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID,
-				"Data format for attachment (" + itos(i) + "), '" + named_formats[p_vertex_formats[i].format] + "', is not valid for a vertex array.");
-
-		// SPIRV-Cross maps `layout(location = <N>) in` to `TEXCOORD<N>`.
-		vdcache.elements_desc.write[i].SemanticName = "TEXCOORD"; // SPIRV-Cross will apply TEXCOORD semantic to vertex attributes.
-		vdcache.elements_desc.write[i].SemanticIndex = p_vertex_formats[i].location;
-		vdcache.elements_desc.write[i].Format = d3d12_formats[p_vertex_formats[i].format].general_format;
-		vdcache.elements_desc.write[i].InputSlot = i; // TODO: Can the same slot be used if data comes from the same buffer (regardless format)?
-		vdcache.elements_desc.write[i].AlignedByteOffset = p_vertex_formats[i].offset;
-		if (p_vertex_formats[i].frequency == VERTEX_FREQUENCY_INSTANCE) {
-			vdcache.elements_desc.write[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
-			vdcache.elements_desc.write[i].InstanceDataStepRate = 1;
-		} else {
-			vdcache.elements_desc.write[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
-			vdcache.elements_desc.write[i].InstanceDataStepRate = 0;
-		}
-		used_locations.insert(p_vertex_formats[i].location);
-	}
-
-	vdcache.vertex_formats = p_vertex_formats;
-
-	VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT);
-	vertex_format_cache[key] = id;
-	vertex_formats[id] = vdcache;
-	return id;
-}
-
-RID RenderingDeviceD3D12::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
-	const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
-
-	ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID());
-
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID());
-	}
-
-	VertexArray vertex_array;
-
-	if (!p_offsets.is_empty()) {
-		ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID());
-	}
-
-	vertex_array.vertex_count = p_vertex_count;
-	vertex_array.description = p_vertex_format;
-	vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.
-	HashSet<Buffer *> unique_buffers;
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);
-
-		const VertexAttribute &atf = vd.vertex_formats[i];
-
-		// Validate with buffer.
-		{
-			uint32_t element_size = get_format_vertex_size(atf.format);
-			ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.
-
-			if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {
-				// Validate size for regular drawing.
-				uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;
-				ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),
-						"Attachment (" + itos(i) + ") will read past the end of the buffer.");
-
-			} else {
-				// Validate size for instances drawing.
-				uint64_t available = buffer->size - atf.offset;
-				ERR_FAIL_COND_V_MSG(available < element_size, RID(),
-						"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");
-
-				uint32_t instances_allowed = available / atf.stride;
-				vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed);
-			}
-		}
-
-		unique_buffers.insert(buffer);
-
-		D3D12_VERTEX_BUFFER_VIEW view = {};
-		uint64_t data_offset = p_offsets.is_empty() ? 0 : p_offsets[i];
-		view.BufferLocation = buffer->resource->GetGPUVirtualAddress() + data_offset;
-		view.SizeInBytes = buffer->size;
-		view.StrideInBytes = atf.stride;
-		vertex_array.views.push_back(view);
-	}
-
-	for (Buffer *buffer : unique_buffers) {
-		vertex_array.unique_buffers.push_back(buffer);
-	}
-
-	RID id = vertex_array_owner.make_rid(vertex_array);
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		_add_dependency(id, p_src_buffers[i]);
-	}
-
-	return id;
-}
-
-RID RenderingDeviceD3D12::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector<uint8_t> &p_data, bool p_use_restart_indices) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_index_count == 0, RID());
-
-	IndexBuffer index_buffer;
-	index_buffer.index_format = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
-	index_buffer.supports_restart_indices = p_use_restart_indices;
-	index_buffer.index_count = p_index_count;
-	uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4);
-#ifdef DEBUG_ENABLED
-	if (p_data.size()) {
-		index_buffer.max_index = 0;
-		ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(),
-				"Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ").");
-		const uint8_t *r = p_data.ptr();
-		if (p_format == INDEX_BUFFER_FORMAT_UINT16) {
-			const uint16_t *index16 = (const uint16_t *)r;
-			for (uint32_t i = 0; i < p_index_count; i++) {
-				if (p_use_restart_indices && index16[i] == 0xFFFF) {
-					continue; // Restart index, ignore.
-				}
-				index_buffer.max_index = MAX(index16[i], index_buffer.max_index);
-			}
-		} else {
-			const uint32_t *index32 = (const uint32_t *)r;
-			for (uint32_t i = 0; i < p_index_count; i++) {
-				if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) {
-					continue; // Restart index, ignore.
-				}
-				index_buffer.max_index = MAX(index32[i], index_buffer.max_index);
-			}
-		}
-	} else {
-		index_buffer.max_index = 0xFFFFFFFF;
-	}
-#else
-	index_buffer.max_index = 0xFFFFFFFF;
-#endif
-	Error err = _buffer_allocate(&index_buffer, size_bytes, D3D12_RESOURCE_STATE_INDEX_BUFFER, D3D12_HEAP_TYPE_DEFAULT);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&index_buffer, 0, r, data_size);
-	}
-	RID id = index_buffer_owner.make_rid(index_buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceD3D12::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID());
-
-	IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_index_buffer);
-
-	ERR_FAIL_COND_V(p_index_count == 0, RID());
-	ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID());
-
-	IndexArray index_array;
-	index_array.buffer = index_buffer;
-	index_array.max_index = index_buffer->max_index;
-	index_array.offset = p_index_offset;
-	index_array.indices = p_index_count;
-	index_array.supports_restart_indices = index_buffer->supports_restart_indices;
-	index_array.view.BufferLocation = index_buffer->resource->GetGPUVirtualAddress();
-	index_array.view.SizeInBytes = p_index_count * (index_buffer->index_format == DXGI_FORMAT_R16_UINT ? 2 : 4);
-	index_array.view.Format = index_buffer->index_format;
-
-	RID id = index_array_owner.make_rid(index_array);
-	_add_dependency(id, p_index_buffer);
-	return id;
-}
-
-/****************/
-/**** SHADER ****/
-/****************/
-
-static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX + 1] = {
-	"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment", "N/A"
-};
-
-static uint32_t shader_stage_bit_offset_indices[RenderingDevice::SHADER_STAGE_MAX] = {
-	/* SHADER_STAGE_VERTEX */ 0,
-	/* SHADER_STAGE_FRAGMENT */ 1,
-	/* SHADER_STAGE_TESSELATION_CONTROL */ UINT32_MAX,
-	/* SHADER_STAGE_TESSELATION_EVALUATION */ UINT32_MAX,
-	/* SHADER_STAGE_COMPUTE */ 2,
-};
-
-String RenderingDeviceD3D12::_shader_uniform_debug(RID p_shader, int p_set) {
-	String ret;
-	const Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, String());
-	for (int i = 0; i < shader->sets.size(); i++) {
-		if (p_set >= 0 && i != p_set) {
-			continue;
-		}
-		for (int j = 0; j < shader->sets[i].uniforms.size(); j++) {
-			const UniformInfo &ui = shader->sets[i].uniforms[j].info;
-			if (!ret.is_empty()) {
-				ret += "\n";
-			}
-			ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length);
-		}
-	}
-	return ret;
-}
-
-uint32_t RenderingDeviceD3D12::_shader_patch_dxil_specialization_constant(
-		PipelineSpecializationConstantType p_type,
-		const void *p_value,
-		const uint64_t (&p_stages_bit_offsets)[D3D12_BITCODE_OFFSETS_NUM_STAGES],
-		HashMap<ShaderStage, Vector<uint8_t>> &r_stages_bytecodes,
-		bool p_is_first_patch) {
-	uint32_t patch_val = 0;
-	switch (p_type) {
-		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT: {
-			uint32_t int_value = *((const int *)p_value);
-			ERR_FAIL_COND_V(int_value & (1 << 31), 0);
-			patch_val = int_value;
-		} break;
-		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL: {
-			bool bool_value = *((const bool *)p_value);
-			patch_val = (uint32_t)bool_value;
-		} break;
-		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT: {
-			uint32_t int_value = *((const int *)p_value);
-			ERR_FAIL_COND_V(int_value & (1 << 31), 0);
-			patch_val = (int_value >> 1);
-		} break;
-	}
-	// For VBR encoding to encode the number of bits we expect (32), we need to set the MSB unconditionally.
-	// However, signed VBR moves the MSB to the LSB, so setting the MSB to 1 wouldn't help. Therefore,
-	// the bit we set to 1 is the one at index 30.
-	patch_val |= (1 << 30);
-	patch_val <<= 1; // What signed VBR does.
-
-	auto tamper_bits = [](uint8_t *p_start, uint64_t p_bit_offset, uint64_t p_value) -> uint64_t {
-		uint64_t original = 0;
-		uint32_t curr_input_byte = p_bit_offset / 8;
-		uint8_t curr_input_bit = p_bit_offset % 8;
-		auto get_curr_input_bit = [&]() -> bool {
-			return ((p_start[curr_input_byte] >> curr_input_bit) & 1);
-		};
-		auto move_to_next_input_bit = [&]() {
-			if (curr_input_bit == 7) {
-				curr_input_bit = 0;
-				curr_input_byte++;
-			} else {
-				curr_input_bit++;
-			}
-		};
-		auto tamper_input_bit = [&](bool p_new_bit) {
-			p_start[curr_input_byte] &= ~((uint8_t)1 << curr_input_bit);
-			if (p_new_bit) {
-				p_start[curr_input_byte] |= (uint8_t)1 << curr_input_bit;
-			}
-		};
-		uint8_t value_bit_idx = 0;
-		for (uint32_t i = 0; i < 5; i++) { // 32 bits take 5 full bytes in VBR.
-			for (uint32_t j = 0; j < 7; j++) {
-				bool input_bit = get_curr_input_bit();
-				original |= (uint64_t)(input_bit ? 1 : 0) << value_bit_idx;
-				tamper_input_bit((p_value >> value_bit_idx) & 1);
-				move_to_next_input_bit();
-				value_bit_idx++;
-			}
-#ifdef DEV_ENABLED
-			bool input_bit = get_curr_input_bit();
-			DEV_ASSERT(i < 4 && input_bit || i == 4 && !input_bit);
-#endif
-			move_to_next_input_bit();
-		}
-		return original;
-	};
-	uint32_t stages_patched_mask = 0;
-	for (int stage = 0; stage < SHADER_STAGE_MAX; stage++) {
-		if (!r_stages_bytecodes.has((ShaderStage)stage)) {
-			continue;
-		}
-
-		uint64_t offset = p_stages_bit_offsets[shader_stage_bit_offset_indices[stage]];
-		if (offset == 0) {
-			// This constant does not appear at this stage.
-			continue;
-		}
-
-		Vector<uint8_t> &bytecode = r_stages_bytecodes[(ShaderStage)stage];
-#ifdef DEV_ENABLED
-		uint64_t orig_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val);
-		// Checking against the value the NIR patch should have set.
-		DEV_ASSERT(!p_is_first_patch || ((orig_patch_val >> 1) & GODOT_NIR_SC_SENTINEL_MAGIC_MASK) == GODOT_NIR_SC_SENTINEL_MAGIC);
-		uint64_t readback_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val);
-		DEV_ASSERT(readback_patch_val == patch_val);
-#else
-		tamper_bits(bytecode.ptrw(), offset, patch_val);
-#endif
-
-		stages_patched_mask |= (1 << stage);
-	}
-	return stages_patched_mask;
-}
-
-bool RenderingDeviceD3D12::_shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob) {
-	dxil_validator *validator = get_dxil_validator_for_current_thread();
-
-	char *err = nullptr;
-	bool res = dxil_validate_module(validator, r_dxil_blob.ptrw(), r_dxil_blob.size(), &err);
-	if (!res) {
-		if (err) {
-			ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(shader_stage_names[p_stage]) + " failed:\n" + String(err));
-		} else {
-			ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(shader_stage_names[p_stage]) + " failed.");
-		}
-	}
-
-	return true;
-}
-
-// Version 1: Initial.
-// Version 2: 64-bit vertex input mask.
-#define SHADER_BINARY_VERSION 2
-
-String RenderingDeviceD3D12::shader_get_binary_cache_key() const {
-	return "D3D12-SV" + itos(SHADER_BINARY_VERSION);
-}
-
-enum RootSignatureLocationType {
-	RS_LOC_TYPE_RESOURCE,
-	RS_LOC_TYPE_SAMPLER,
-};
-
-enum ResourceClass {
-	RES_CLASS_INVALID,
-	RES_CLASS_CBV,
-	RES_CLASS_SRV,
-	RES_CLASS_UAV,
-};
-
-// Phase 1: SPIR-V reflection, where the Vulkan/RD interface of the shader is discovered.
-// Phase 2: SPIR-V to DXIL translation, where the DXIL interface is discovered, which may have gaps due to optimizations.
-
-struct RenderingDeviceD3D12ShaderBinaryDataBinding {
-	// - Phase 1.
-	uint32_t type;
-	uint32_t binding;
-	uint32_t stages;
-	uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
-	uint32_t writable;
-	// - Phase 2.
-	uint32_t res_class;
-	uint32_t has_sampler;
-	uint32_t dxil_stages;
-	struct RootSignatureLocation {
-		uint32_t root_param_idx = UINT32_MAX; // UINT32_MAX if unused.
-		uint32_t range_idx = UINT32_MAX; // UINT32_MAX if unused.
-	};
-	RootSignatureLocation root_sig_locations[2]; // Index is RootSignatureLocationType.
-
-	// We need to sort these to fill the root signature locations properly.
-	bool operator<(const RenderingDeviceD3D12ShaderBinaryDataBinding &p_other) const {
-		return binding < p_other.binding;
-	}
-};
-
-struct RenderingDeviceD3D12ShaderBinarySpecializationConstant {
-	// - Phase 1.
-	uint32_t type;
-	uint32_t constant_id;
-	union {
-		uint32_t int_value;
-		float float_value;
-		bool bool_value;
-	};
-	// - Phase 2.
-	uint64_t stages_bit_offsets[D3D12_BITCODE_OFFSETS_NUM_STAGES];
-};
-
-struct RenderingDeviceD3D12ShaderBinaryData {
-	uint64_t vertex_input_mask;
-	uint32_t fragment_output_mask;
-	uint32_t specialization_constants_count;
-	uint32_t spirv_specialization_constants_ids_mask;
-	uint32_t is_compute;
-	uint32_t compute_local_size[3];
-	uint32_t set_count;
-	uint32_t push_constant_size;
-	uint32_t dxil_push_constant_stages; // Phase 2.
-	uint32_t nir_runtime_data_root_param_idx; // Phase 2.
-	uint32_t stage_count;
-	uint32_t shader_name_len;
-	uint32_t root_signature_len;
-	uint32_t root_signature_crc;
-};
-
-Vector<uint8_t> RenderingDeviceD3D12::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
-	SpirvReflectionData spirv_data;
-	if (_reflect_spirv(p_spirv, spirv_data) != OK) {
-		return Vector<uint8_t>();
-	}
-
-	// Collect reflection data into binary data.
-	RenderingDeviceD3D12ShaderBinaryData binary_data = {};
-	Vector<Vector<RenderingDeviceD3D12ShaderBinaryDataBinding>> uniform_info;
-	Vector<RenderingDeviceD3D12ShaderBinarySpecializationConstant> specialization_constants;
-	{
-		binary_data.vertex_input_mask = spirv_data.vertex_input_mask;
-		binary_data.fragment_output_mask = spirv_data.fragment_output_mask;
-		binary_data.specialization_constants_count = spirv_data.specialization_constants.size();
-		binary_data.is_compute = spirv_data.is_compute;
-		binary_data.compute_local_size[0] = spirv_data.compute_local_size[0];
-		binary_data.compute_local_size[1] = spirv_data.compute_local_size[1];
-		binary_data.compute_local_size[2] = spirv_data.compute_local_size[2];
-		binary_data.set_count = spirv_data.uniforms.size();
-		binary_data.push_constant_size = spirv_data.push_constant_size;
-		binary_data.nir_runtime_data_root_param_idx = UINT32_MAX;
-		binary_data.stage_count = p_spirv.size();
-
-		for (const Vector<SpirvReflectionData::Uniform> &spirv_set : spirv_data.uniforms) {
-			Vector<RenderingDeviceD3D12ShaderBinaryDataBinding> set_bindings;
-			for (const SpirvReflectionData::Uniform &spirv_uniform : spirv_set) {
-				RenderingDeviceD3D12ShaderBinaryDataBinding binding{};
-				binding.type = (uint32_t)spirv_uniform.type;
-				binding.binding = spirv_uniform.binding;
-				binding.stages = (uint32_t)spirv_uniform.stages_mask;
-				binding.length = spirv_uniform.length;
-				binding.writable = (uint32_t)spirv_uniform.writable;
-				set_bindings.push_back(binding);
-			}
-			uniform_info.push_back(set_bindings);
-		}
-
-		for (const SpirvReflectionData::SpecializationConstant &spirv_sc : spirv_data.specialization_constants) {
-			RenderingDeviceD3D12ShaderBinarySpecializationConstant spec_constant{};
-			spec_constant.type = (uint32_t)spirv_sc.type;
-			spec_constant.constant_id = spirv_sc.constant_id;
-			spec_constant.int_value = spirv_sc.int_value;
-			specialization_constants.push_back(spec_constant);
-
-			binary_data.spirv_specialization_constants_ids_mask |= (1 << spirv_sc.constant_id);
-		}
-	}
-
-	// Translate SPIR-V shaders to DXIL, and collect shader info from the new representation.
-	HashMap<ShaderStage, Vector<uint8_t>> dxil_blobs;
-	BitField<ShaderStage> stages_processed;
-	{
-		HashMap<int, nir_shader *> stages_nir_shaders;
-
-		auto free_nir_shaders = [&]() {
-			for (KeyValue<int, nir_shader *> &E : stages_nir_shaders) {
-				ralloc_free(E.value);
-			}
-			stages_nir_shaders.clear();
-		};
-
-		// This is based on spirv2dxil.c. May need updates when it changes.
-		// Also, this has to stay around until after linking.
-		nir_shader_compiler_options nir_options = *dxil_get_nir_compiler_options();
-		nir_options.lower_base_vertex = false;
-
-		dxil_spirv_runtime_conf dxil_runtime_conf = {};
-		dxil_runtime_conf.runtime_data_cbv.register_space = RUNTIME_DATA_SPACE;
-		dxil_runtime_conf.runtime_data_cbv.base_shader_register = RUNTIME_DATA_REGISTER;
-		dxil_runtime_conf.push_constant_cbv.register_space = ROOT_CONSTANT_SPACE;
-		dxil_runtime_conf.push_constant_cbv.base_shader_register = ROOT_CONSTANT_REGISTER;
-		dxil_runtime_conf.zero_based_vertex_instance_id = true;
-		dxil_runtime_conf.zero_based_compute_workgroup_id = true;
-		dxil_runtime_conf.declared_read_only_images_as_srvs = true;
-		// Making this explicit to let maintainers know that in practice this didn't improve performance,
-		// probably because data generated by one shader and consumed by another one forces the resource
-		// to transition from UAV to SRV, and back, instead of being an UAV all the time.
-		// In case someone wants to try, care must be taken so in case of incompatible bindings across stages
-		// happen as a result, all the stages are re-translated. That can happen if, for instance, a stage only
-		// uses an allegedly writable resource only for reading but the next stage doesn't.
-		dxil_runtime_conf.inferred_read_only_images_as_srvs = false;
-
-		// - Translate SPIR-V to NIR.
-		for (int i = 0; i < p_spirv.size(); i++) {
-			ShaderStage stage = (ShaderStage)p_spirv[i].shader_stage;
-			ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage);
-
-			stages_processed.set_flag(stage_flag);
-
-			{
-				char *entry_point = "main";
-
-				static const gl_shader_stage SPIRV_TO_MESA_STAGES[SHADER_STAGE_MAX] = {
-					/* SHADER_STAGE_VERTEX */ MESA_SHADER_VERTEX,
-					/* SHADER_STAGE_FRAGMENT */ MESA_SHADER_FRAGMENT,
-					/* SHADER_STAGE_TESSELATION_CONTROL */ MESA_SHADER_TESS_CTRL,
-					/* SHADER_STAGE_TESSELATION_EVALUATION */ MESA_SHADER_TESS_EVAL,
-					/* SHADER_STAGE_COMPUTE */ MESA_SHADER_COMPUTE,
-				};
-
-				nir_shader *nir_shader = spirv_to_nir(
-						(const uint32_t *)p_spirv[i].spir_v.ptr(),
-						p_spirv[i].spir_v.size() / sizeof(uint32_t),
-						nullptr,
-						0,
-						SPIRV_TO_MESA_STAGES[stage],
-						entry_point,
-						dxil_spirv_nir_get_spirv_options(), &nir_options);
-				if (!nir_shader) {
-					free_nir_shaders();
-					ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader translation (step 1) at stage " + String(shader_stage_names[stage]) + " failed.");
-				}
-
-#ifdef DEV_ENABLED
-				nir_validate_shader(nir_shader, "Validate before feeding NIR to the DXIL compiler");
-#endif
-
-				if (stage == SHADER_STAGE_VERTEX) {
-					dxil_runtime_conf.yz_flip.y_mask = 0xffff;
-					dxil_runtime_conf.yz_flip.mode = DXIL_SPIRV_Y_FLIP_UNCONDITIONAL;
-				} else {
-					dxil_runtime_conf.yz_flip.y_mask = 0;
-					dxil_runtime_conf.yz_flip.mode = DXIL_SPIRV_YZ_FLIP_NONE;
-				}
-
-				// This is based on spirv2dxil.c. May need updates when it changes.
-				dxil_spirv_nir_prep(nir_shader);
-				bool requires_runtime_data = {};
-				dxil_spirv_nir_passes(nir_shader, &dxil_runtime_conf, &requires_runtime_data);
-
-				stages_nir_shaders[stage] = nir_shader;
-			}
-		}
-
-		// - Link NIR shaders.
-		for (int i = SHADER_STAGE_MAX - 1; i >= 0; i--) {
-			if (!stages_nir_shaders.has(i)) {
-				continue;
-			}
-			nir_shader *shader = stages_nir_shaders[i];
-			nir_shader *prev_shader = nullptr;
-			for (int j = i - 1; j >= 0; j--) {
-				if (stages_nir_shaders.has(j)) {
-					prev_shader = stages_nir_shaders[j];
-					break;
-				}
-			}
-			if (prev_shader) {
-				bool requires_runtime_data = {};
-				dxil_spirv_nir_link(shader, prev_shader, &dxil_runtime_conf, &requires_runtime_data);
-			}
-		}
-
-		// - Translate NIR to DXIL.
-		for (int i = 0; i < p_spirv.size(); i++) {
-			ShaderStage stage = (ShaderStage)p_spirv[i].shader_stage;
-
-			struct ShaderData {
-				ShaderStage stage;
-				RenderingDeviceD3D12ShaderBinaryData &binary_data;
-				Vector<Vector<RenderingDeviceD3D12ShaderBinaryDataBinding>> &uniform_info;
-				Vector<RenderingDeviceD3D12ShaderBinarySpecializationConstant> &specialization_constants;
-			} shader_data{ stage, binary_data, uniform_info, specialization_constants };
-
-			GodotNirCallbacks godot_nir_callbacks = {};
-			godot_nir_callbacks.data = &shader_data;
-
-			godot_nir_callbacks.report_resource = [](uint32_t p_register, uint32_t p_space, uint32_t p_dxil_type, void *p_data) {
-				ShaderData &shader_data = *(ShaderData *)p_data;
-
-				// Types based on Mesa's dxil_container.h.
-				static const uint32_t DXIL_RES_SAMPLER = 1;
-				static const ResourceClass DXIL_TYPE_TO_CLASS[] = {
-					/* DXIL_RES_INVALID */ RES_CLASS_INVALID,
-					/* DXIL_RES_SAMPLER */ RES_CLASS_INVALID, // Handling sampler as a flag.
-					/* DXIL_RES_CBV */ RES_CLASS_CBV,
-					/* DXIL_RES_SRV_TYPED */ RES_CLASS_SRV,
-					/* DXIL_RES_SRV_RAW */ RES_CLASS_SRV,
-					/* DXIL_RES_SRV_STRUCTURED */ RES_CLASS_SRV,
-					/* DXIL_RES_UAV_TYPED */ RES_CLASS_UAV,
-					/* DXIL_RES_UAV_RAW */ RES_CLASS_UAV,
-					/* DXIL_RES_UAV_STRUCTURED */ RES_CLASS_UAV,
-					/* DXIL_RES_UAV_STRUCTURED_WITH_COUNTER */ RES_CLASS_INVALID,
-				};
-				DEV_ASSERT(p_dxil_type < ARRAY_SIZE(DXIL_TYPE_TO_CLASS));
-				ResourceClass res_class = DXIL_TYPE_TO_CLASS[p_dxil_type];
-
-				if (p_register == ROOT_CONSTANT_REGISTER && p_space == ROOT_CONSTANT_SPACE) {
-					DEV_ASSERT(res_class == RES_CLASS_CBV);
-					shader_data.binary_data.dxil_push_constant_stages |= (1 << shader_data.stage);
-				} else if (p_register == RUNTIME_DATA_REGISTER && p_space == RUNTIME_DATA_SPACE) {
-					DEV_ASSERT(res_class == RES_CLASS_CBV);
-					shader_data.binary_data.nir_runtime_data_root_param_idx = 1; // Temporary, to be determined later.
-				} else {
-					DEV_ASSERT(p_space == 0);
-
-					uint32_t set = p_register / GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER;
-					uint32_t binding = (p_register % GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER) / GODOT_NIR_BINDING_MULTIPLIER;
-
-					DEV_ASSERT(set < (uint32_t)shader_data.uniform_info.size());
-					bool found = false;
-					for (int i = 0; i < shader_data.uniform_info[set].size(); i++) {
-						if (shader_data.uniform_info[set][i].binding != binding) {
-							continue;
-						}
-
-						RenderingDeviceD3D12ShaderBinaryDataBinding &binding_info = shader_data.uniform_info.write[set].write[i];
-
-						binding_info.dxil_stages |= (1 << shader_data.stage);
-
-						if (res_class != RES_CLASS_INVALID) {
-							DEV_ASSERT(binding_info.res_class == (uint32_t)RES_CLASS_INVALID || binding_info.res_class == (uint32_t)res_class);
-							binding_info.res_class = res_class;
-						} else if (p_dxil_type == DXIL_RES_SAMPLER) {
-							binding_info.has_sampler = (uint32_t) true;
-						} else {
-							CRASH_NOW();
-						}
-
-						found = true;
-						break;
-					}
-					DEV_ASSERT(found);
-				}
-			};
-
-			godot_nir_callbacks.report_sc_bit_offset_fn = [](uint32_t p_sc_id, uint64_t p_bit_offset, void *p_data) {
-				ShaderData &shader_data = *(ShaderData *)p_data;
-
-				bool found = false;
-				for (int i = 0; i < shader_data.specialization_constants.size(); i++) {
-					if (shader_data.specialization_constants[i].constant_id != p_sc_id) {
-						continue;
-					}
-
-					uint32_t offset_idx = shader_stage_bit_offset_indices[shader_data.stage];
-					DEV_ASSERT(shader_data.specialization_constants.write[i].stages_bit_offsets[offset_idx] == 0);
-					shader_data.specialization_constants.write[i].stages_bit_offsets[offset_idx] = p_bit_offset;
-
-					found = true;
-					break;
-				}
-				DEV_ASSERT(found);
-			};
-
-			godot_nir_callbacks.report_bitcode_bit_offset_fn = [](uint64_t p_bit_offset, void *p_data) {
-				DEV_ASSERT(p_bit_offset % 8 == 0);
-				ShaderData &shader_data = *(ShaderData *)p_data;
-				uint32_t offset_idx = shader_stage_bit_offset_indices[shader_data.stage];
-				for (int i = 0; i < shader_data.specialization_constants.size(); i++) {
-					if (shader_data.specialization_constants.write[i].stages_bit_offsets[offset_idx] == 0) {
-						// This SC has been optimized out from this stage.
-						continue;
-					}
-					shader_data.specialization_constants.write[i].stages_bit_offsets[offset_idx] += p_bit_offset;
-				}
-			};
-
-			auto shader_model_d3d_to_dxil = [](D3D_SHADER_MODEL p_d3d_shader_model) -> dxil_shader_model {
-				static_assert(SHADER_MODEL_6_0 == 0x60000);
-				static_assert(SHADER_MODEL_6_3 == 0x60003);
-				static_assert(D3D_SHADER_MODEL_6_0 == 0x60);
-				static_assert(D3D_SHADER_MODEL_6_3 == 0x63);
-				return (dxil_shader_model)((p_d3d_shader_model >> 4) * 0x10000 + (p_d3d_shader_model & 0xf));
-			};
-
-			nir_to_dxil_options nir_to_dxil_options = {};
-			nir_to_dxil_options.environment = DXIL_ENVIRONMENT_VULKAN;
-			nir_to_dxil_options.shader_model_max = shader_model_d3d_to_dxil(context->get_shader_capabilities().shader_model);
-			nir_to_dxil_options.validator_version_max = dxil_get_validator_version(get_dxil_validator_for_current_thread());
-			nir_to_dxil_options.godot_nir_callbacks = &godot_nir_callbacks;
-
-			dxil_logger logger = {};
-			logger.log = [](void *p_priv, const char *p_msg) {
-#ifdef DEBUG_ENABLED
-				print_verbose(p_msg);
-#endif
-			};
-
-			blob dxil_blob = {};
-			bool ok = nir_to_dxil(stages_nir_shaders[stage], &nir_to_dxil_options, &logger, &dxil_blob);
-			ralloc_free(stages_nir_shaders[stage]);
-			stages_nir_shaders.erase(stage);
-			if (!ok) {
-				free_nir_shaders();
-				ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader translation at stage " + String(shader_stage_names[stage]) + " failed.");
-			}
-
-			Vector<uint8_t> blob_copy;
-			blob_copy.resize(dxil_blob.size);
-			memcpy(blob_copy.ptrw(), dxil_blob.data, dxil_blob.size);
-			blob_finish(&dxil_blob);
-			dxil_blobs.insert(stage, blob_copy);
-		}
-	}
-
-#if 0
-	if (dxil_blobs.has(SHADER_STAGE_FRAGMENT)) {
-		Ref<FileAccess> f = FileAccess::open("res://1.dxil", FileAccess::WRITE);
-		f->store_buffer(dxil_blobs[SHADER_STAGE_FRAGMENT].ptr(), dxil_blobs[SHADER_STAGE_FRAGMENT].size());
-	}
-#endif
-
-	// Patch with default values of specialization constants.
-	if (specialization_constants.size()) {
-		for (const RenderingDeviceD3D12ShaderBinarySpecializationConstant &sc : specialization_constants) {
-			_shader_patch_dxil_specialization_constant((PipelineSpecializationConstantType)sc.type, &sc.int_value, sc.stages_bit_offsets, dxil_blobs, true);
-		}
-#if 0
-		if (dxil_blobs.has(SHADER_STAGE_FRAGMENT)) {
-			Ref<FileAccess> f = FileAccess::open("res://2.dxil", FileAccess::WRITE);
-			f->store_buffer(dxil_blobs[SHADER_STAGE_FRAGMENT].ptr(), dxil_blobs[SHADER_STAGE_FRAGMENT].size());
-		}
-#endif
-	}
-
-	// Sign.
-	for (KeyValue<ShaderStage, Vector<uint8_t>> &E : dxil_blobs) {
-		ShaderStage stage = E.key;
-		Vector<uint8_t> &dxil_blob = E.value;
-		bool sign_ok = _shader_sign_dxil_bytecode(stage, dxil_blob);
-		ERR_FAIL_COND_V(!sign_ok, Vector<uint8_t>());
-	}
-
-	// Build the root signature.
-	ComPtr<ID3DBlob> root_sig_blob;
-	{
-		auto stages_to_d3d12_visibility = [](uint32_t p_stages_mask) -> D3D12_SHADER_VISIBILITY {
-			switch (p_stages_mask) {
-				case SHADER_STAGE_VERTEX_BIT: {
-					return D3D12_SHADER_VISIBILITY_VERTEX;
-				}
-				case SHADER_STAGE_FRAGMENT_BIT: {
-					return D3D12_SHADER_VISIBILITY_PIXEL;
-				}
-				default: {
-					return D3D12_SHADER_VISIBILITY_ALL;
-				}
-			}
-		};
-
-		LocalVector<D3D12_ROOT_PARAMETER1> root_params;
-
-		// Root (push) constants.
-		if (binary_data.dxil_push_constant_stages) {
-			CD3DX12_ROOT_PARAMETER1 push_constant;
-			push_constant.InitAsConstants(
-					binary_data.push_constant_size / sizeof(uint32_t),
-					ROOT_CONSTANT_REGISTER,
-					ROOT_CONSTANT_SPACE,
-					stages_to_d3d12_visibility(binary_data.dxil_push_constant_stages));
-			root_params.push_back(push_constant);
-		}
-
-		// NIR-DXIL runtime data.
-		if (binary_data.nir_runtime_data_root_param_idx == 1) { // Set above to 1 when discovering runtime data is needed.
-			DEV_ASSERT(!binary_data.is_compute); // Could be supported if needed, but it's pointless as of now.
-			binary_data.nir_runtime_data_root_param_idx = root_params.size();
-			CD3DX12_ROOT_PARAMETER1 nir_runtime_data;
-			nir_runtime_data.InitAsConstants(
-					sizeof(dxil_spirv_vertex_runtime_data) / sizeof(uint32_t),
-					RUNTIME_DATA_REGISTER,
-					RUNTIME_DATA_SPACE,
-					D3D12_SHADER_VISIBILITY_VERTEX);
-			root_params.push_back(nir_runtime_data);
-		}
-
-		// Descriptor tables (up to two per uniform set, for resources and/or samplers).
-
-		// These have to stay around until serialization!
-		struct TraceableDescriptorTable {
-			uint32_t stages_mask = {};
-			Vector<D3D12_DESCRIPTOR_RANGE1> ranges;
-			Vector<RenderingDeviceD3D12ShaderBinaryDataBinding::RootSignatureLocation *> root_sig_locations;
-		};
-		Vector<TraceableDescriptorTable> resource_tables_maps;
-		Vector<TraceableDescriptorTable> sampler_tables_maps;
-
-		for (int set = 0; set < uniform_info.size(); set++) {
-			bool first_resource_in_set = true;
-			bool first_sampler_in_set = true;
-			uniform_info.write[set].sort();
-			for (int i = 0; i < uniform_info[set].size(); i++) {
-				const RenderingDeviceD3D12ShaderBinaryDataBinding &binding = uniform_info[set][i];
-
-				bool really_used = binding.dxil_stages != 0;
-#ifdef DEV_ENABLED
-				bool anybody_home = (ResourceClass)binding.res_class != RES_CLASS_INVALID || binding.has_sampler;
-				DEV_ASSERT(anybody_home == really_used);
-#endif
-				if (!really_used) {
-					continue; // Existed in SPIR-V; went away in DXIL.
-				}
-
-				auto insert_range = [](D3D12_DESCRIPTOR_RANGE_TYPE p_range_type,
-											uint32_t p_num_descriptors,
-											uint32_t p_dxil_register,
-											uint32_t p_dxil_stages_mask,
-											RenderingDeviceD3D12ShaderBinaryDataBinding::RootSignatureLocation(&p_root_sig_locations),
-											Vector<TraceableDescriptorTable> &r_tables,
-											bool &r_first_in_set) {
-					if (r_first_in_set) {
-						r_tables.resize(r_tables.size() + 1);
-						r_first_in_set = false;
-					}
-					TraceableDescriptorTable &table = r_tables.write[r_tables.size() - 1];
-					table.stages_mask |= p_dxil_stages_mask;
-
-					CD3DX12_DESCRIPTOR_RANGE1 range;
-					// Due to the aliasing hack for SRV-UAV of different families,
-					// we can be causing an unintended change of data (sometimes the validation layers catch it).
-					D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
-					if (p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) {
-						flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
-					} else if (p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_CBV) {
-						flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE;
-					}
-					range.Init(p_range_type, p_num_descriptors, p_dxil_register, 0, flags);
-
-					table.ranges.push_back(range);
-					table.root_sig_locations.push_back(&p_root_sig_locations);
-				};
-
-				uint32_t num_descriptors = 1;
-
-				D3D12_DESCRIPTOR_RANGE_TYPE resource_range_type = {};
-				switch ((ResourceClass)binding.res_class) {
-					case RES_CLASS_INVALID: {
-						num_descriptors = binding.length;
-						DEV_ASSERT(binding.has_sampler);
-					} break;
-					case RES_CLASS_CBV: {
-						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
-						DEV_ASSERT(!binding.has_sampler);
-					} break;
-					case RES_CLASS_SRV: {
-						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
-						num_descriptors = MAX(1u, binding.length); // An unbound R/O buffer is reflected as zero-size.
-					} break;
-					case RES_CLASS_UAV: {
-						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
-						num_descriptors = MAX(1u, binding.length); // An unbound R/W buffer is reflected as zero-size.
-						DEV_ASSERT(!binding.has_sampler);
-					} break;
-				}
-
-				uint32_t dxil_register = set * GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER + binding.binding * GODOT_NIR_BINDING_MULTIPLIER;
-
-				if (binding.res_class != RES_CLASS_INVALID) {
-					insert_range(
-							resource_range_type,
-							num_descriptors,
-							dxil_register,
-							uniform_info[set][i].dxil_stages,
-							uniform_info.write[set].write[i].root_sig_locations[RS_LOC_TYPE_RESOURCE],
-							resource_tables_maps,
-							first_resource_in_set);
-				}
-				if (binding.has_sampler) {
-					insert_range(
-							D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
-							num_descriptors,
-							dxil_register,
-							uniform_info[set][i].dxil_stages,
-							uniform_info.write[set].write[i].root_sig_locations[RS_LOC_TYPE_SAMPLER],
-							sampler_tables_maps,
-							first_sampler_in_set);
-				}
-			}
-		}
-
-		auto make_descriptor_tables = [&root_params, &stages_to_d3d12_visibility](const Vector<TraceableDescriptorTable> &p_tables) {
-			for (const TraceableDescriptorTable &table : p_tables) {
-				D3D12_SHADER_VISIBILITY visibility = stages_to_d3d12_visibility(table.stages_mask);
-				DEV_ASSERT(table.ranges.size() == table.root_sig_locations.size());
-				for (int i = 0; i < table.ranges.size(); i++) {
-					// By now we know very well which root signature location corresponds to the pointed uniform.
-					table.root_sig_locations[i]->root_param_idx = root_params.size();
-					table.root_sig_locations[i]->range_idx = i;
-				}
-
-				CD3DX12_ROOT_PARAMETER1 root_table;
-				root_table.InitAsDescriptorTable(table.ranges.size(), table.ranges.ptr(), visibility);
-				root_params.push_back(root_table);
-			}
-		};
-
-		make_descriptor_tables(resource_tables_maps);
-		make_descriptor_tables(sampler_tables_maps);
-
-		CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {};
-		D3D12_ROOT_SIGNATURE_FLAGS root_sig_flags =
-				D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
-				D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
-				D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
-				D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |
-				D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS;
-		if (!stages_processed.has_flag(SHADER_STAGE_VERTEX_BIT)) {
-			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS;
-		}
-		if (!stages_processed.has_flag(SHADER_STAGE_FRAGMENT_BIT)) {
-			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
-		}
-		if (binary_data.vertex_input_mask) {
-			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
-		}
-		root_sig_desc.Init_1_1(root_params.size(), root_params.ptr(), 0, nullptr, root_sig_flags);
-
-		ComPtr<ID3DBlob> error_blob;
-		HRESULT res = D3DX12SerializeVersionedRootSignature(&root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf());
-		ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(),
-				"Serialization of root signature failed with error " + vformat("0x%08ux", res) + " and the following message:\n" + String((char *)error_blob->GetBufferPointer(), error_blob->GetBufferSize()));
-
-		binary_data.root_signature_crc = crc32(0, nullptr, 0);
-		binary_data.root_signature_crc = crc32(binary_data.root_signature_crc, (const Bytef *)root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize());
-	}
-
-	Vector<Vector<uint8_t>> compressed_stages;
-	Vector<uint32_t> zstd_size;
-
-	uint32_t stages_binary_size = 0;
-
-	for (int i = 0; i < p_spirv.size(); i++) {
-		Vector<uint8_t> zstd;
-		Vector<uint8_t> &dxil_blob = dxil_blobs[p_spirv[i].shader_stage];
-		zstd.resize(Compression::get_max_compressed_buffer_size(dxil_blob.size(), Compression::MODE_ZSTD));
-		int dst_size = Compression::compress(zstd.ptrw(), dxil_blob.ptr(), dxil_blob.size(), Compression::MODE_ZSTD);
-
-		zstd_size.push_back(dst_size);
-		zstd.resize(dst_size);
-		compressed_stages.push_back(zstd);
-
-		uint32_t s = compressed_stages[i].size();
-		if (s % 4 != 0) {
-			s += 4 - (s % 4);
-		}
-		stages_binary_size += s;
-	}
-
-	CharString shader_name_utf = p_shader_name.utf8();
-
-	binary_data.shader_name_len = shader_name_utf.length();
-
-	uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
-	total_size += sizeof(RenderingDeviceD3D12ShaderBinaryData);
-
-	total_size += binary_data.shader_name_len;
-	if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-		total_size += 4 - (binary_data.shader_name_len % 4);
-	}
-
-	for (int i = 0; i < uniform_info.size(); i++) {
-		total_size += sizeof(uint32_t);
-		total_size += uniform_info[i].size() * sizeof(RenderingDeviceD3D12ShaderBinaryDataBinding);
-	}
-
-	total_size += sizeof(RenderingDeviceD3D12ShaderBinarySpecializationConstant) * specialization_constants.size();
-
-	total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
-	total_size += stages_binary_size;
-
-	binary_data.root_signature_len = root_sig_blob->GetBufferSize();
-	total_size += binary_data.root_signature_len;
-
-	Vector<uint8_t> ret;
-	ret.resize(total_size);
-	{
-		uint32_t offset = 0;
-		uint8_t *binptr = ret.ptrw();
-		binptr[0] = 'G';
-		binptr[1] = 'S';
-		binptr[2] = 'B';
-		binptr[3] = 'D'; // Godot shader binary data.
-		offset += 4;
-		encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
-		offset += sizeof(uint32_t);
-		encode_uint32(sizeof(RenderingDeviceD3D12ShaderBinaryData), binptr + offset);
-		offset += sizeof(uint32_t);
-		memcpy(binptr + offset, &binary_data, sizeof(RenderingDeviceD3D12ShaderBinaryData));
-		offset += sizeof(RenderingDeviceD3D12ShaderBinaryData);
-
-		if (binary_data.shader_name_len > 0) {
-			memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
-			offset += binary_data.shader_name_len;
-
-			if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-				offset += 4 - (binary_data.shader_name_len % 4);
-			}
-		}
-
-		for (int i = 0; i < uniform_info.size(); i++) {
-			int count = uniform_info[i].size();
-			encode_uint32(count, binptr + offset);
-			offset += sizeof(uint32_t);
-			if (count > 0) {
-				memcpy(binptr + offset, uniform_info[i].ptr(), sizeof(RenderingDeviceD3D12ShaderBinaryDataBinding) * count);
-				offset += sizeof(RenderingDeviceD3D12ShaderBinaryDataBinding) * count;
-			}
-		}
-
-		if (specialization_constants.size()) {
-			memcpy(binptr + offset, specialization_constants.ptr(), sizeof(RenderingDeviceD3D12ShaderBinarySpecializationConstant) * specialization_constants.size());
-			offset += sizeof(RenderingDeviceD3D12ShaderBinarySpecializationConstant) * specialization_constants.size();
-		}
-
-		for (int i = 0; i < compressed_stages.size(); i++) {
-			encode_uint32(p_spirv[i].shader_stage, binptr + offset);
-			offset += sizeof(uint32_t);
-			encode_uint32(dxil_blobs[p_spirv[i].shader_stage].size(), binptr + offset);
-			offset += sizeof(uint32_t);
-			encode_uint32(zstd_size[i], binptr + offset);
-			offset += sizeof(uint32_t);
-			memcpy(binptr + offset, compressed_stages[i].ptr(), compressed_stages[i].size());
-
-			uint32_t s = compressed_stages[i].size();
-
-			if (s % 4 != 0) {
-				s += 4 - (s % 4);
-			}
-
-			offset += s;
-		}
-
-		memcpy(binptr + offset, root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize());
-		offset += root_sig_blob->GetBufferSize();
-
-		ERR_FAIL_COND_V(offset != (uint32_t)ret.size(), Vector<uint8_t>());
-	}
-
-	return ret;
-}
-
-RID RenderingDeviceD3D12::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) {
-	const uint8_t *binptr = p_shader_binary.ptr();
-	uint32_t binsize = p_shader_binary.size();
-
-	uint32_t read_offset = 0;
-	// Consistency check.
-	ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceD3D12ShaderBinaryData), RID());
-	ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', RID());
-
-	uint32_t bin_version = decode_uint32(binptr + 4);
-	ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID());
-
-	uint32_t bin_data_size = decode_uint32(binptr + 8);
-
-	const RenderingDeviceD3D12ShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceD3D12ShaderBinaryData *>(binptr + 12));
-
-	uint64_t vertex_input_mask = binary_data.vertex_input_mask;
-
-	uint32_t fragment_output_mask = binary_data.fragment_output_mask;
-
-	bool is_compute = binary_data.is_compute;
-
-	const uint32_t compute_local_size[3] = { binary_data.compute_local_size[0], binary_data.compute_local_size[1], binary_data.compute_local_size[2] };
-
-	read_offset += sizeof(uint32_t) * 3 + bin_data_size;
-
-	String name;
-
-	if (binary_data.shader_name_len) {
-		name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
-		read_offset += binary_data.shader_name_len;
-		if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-			read_offset += 4 - (binary_data.shader_name_len % 4);
-		}
-	}
-
-	Vector<Shader::Set> set_info;
-	set_info.resize(binary_data.set_count);
-
-	for (uint32_t i = 0; i < binary_data.set_count; i++) {
-		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, RID());
-		uint32_t set_count = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		const RenderingDeviceD3D12ShaderBinaryDataBinding *set_ptr = reinterpret_cast<const RenderingDeviceD3D12ShaderBinaryDataBinding *>(binptr + read_offset);
-		uint32_t set_size = set_count * sizeof(RenderingDeviceD3D12ShaderBinaryDataBinding);
-		ERR_FAIL_COND_V(read_offset + set_size >= binsize, RID());
-
-		for (uint32_t j = 0; j < set_count; j++) {
-			Shader::ShaderUniformInfo sui;
-
-			sui.info.type = UniformType(set_ptr[j].type);
-			sui.info.writable = set_ptr[j].writable;
-			sui.info.length = set_ptr[j].length;
-			sui.info.binding = set_ptr[j].binding;
-
-			sui.binding.stages = set_ptr[j].dxil_stages;
-			sui.binding.res_class = (ResourceClass)set_ptr[j].res_class;
-			static_assert(sizeof(UniformBindingInfo::root_sig_locations) == sizeof(RenderingDeviceD3D12ShaderBinaryDataBinding::root_sig_locations));
-			memcpy(&sui.binding.root_sig_locations, &set_ptr[j].root_sig_locations, sizeof(UniformBindingInfo::root_sig_locations));
-
-			set_info.write[i].uniforms.push_back(sui);
-
-			if (sui.binding.root_sig_locations.resource.root_param_idx != UINT32_MAX) {
-				set_info.write[i].num_root_params.resources++;
-			}
-			if (sui.binding.root_sig_locations.sampler.root_param_idx != UINT32_MAX) {
-				set_info.write[i].num_root_params.samplers++;
-			}
-		}
-
-		read_offset += set_size;
-	}
-
-	ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(RenderingDeviceD3D12ShaderBinarySpecializationConstant) >= binsize, RID());
-
-	Vector<Shader::SpecializationConstant> specialization_constants;
-
-	for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
-		const RenderingDeviceD3D12ShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceD3D12ShaderBinarySpecializationConstant *>(binptr + read_offset));
-		Shader::SpecializationConstant sc;
-		sc.constant.int_value = src_sc.int_value;
-		sc.constant.type = PipelineSpecializationConstantType(src_sc.type);
-		sc.constant.constant_id = src_sc.constant_id;
-		memcpy(sc.stages_bit_offsets, src_sc.stages_bit_offsets, sizeof(sc.stages_bit_offsets));
-		specialization_constants.push_back(sc);
-
-		read_offset += sizeof(RenderingDeviceD3D12ShaderBinarySpecializationConstant);
-	}
-
-	HashMap<ShaderStage, Vector<uint8_t>> stages_bytecode;
-
-	for (uint32_t i = 0; i < binary_data.stage_count; i++) {
-		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, RID());
-		uint32_t stage = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		uint32_t dxil_size = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		uint32_t zstd_size = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-
-		// Decompress.
-		Vector<uint8_t> dxil;
-		dxil.resize(dxil_size);
-		int dec_dxil_size = Compression::decompress(dxil.ptrw(), dxil.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
-		ERR_FAIL_COND_V(dec_dxil_size != (int32_t)dxil_size, RID());
-		stages_bytecode[ShaderStage(stage)] = dxil;
-
-		if (zstd_size % 4 != 0) {
-			zstd_size += 4 - (zstd_size % 4);
-		}
-
-		ERR_FAIL_COND_V(read_offset + zstd_size > binsize, RID());
-
-		read_offset += zstd_size;
-	}
-
-	const uint8_t *root_sig_data_ptr = binptr + read_offset;
-
-	ComPtr<ID3D12RootSignatureDeserializer> root_sig_deserializer;
-	HRESULT res = D3D12CreateRootSignatureDeserializer(root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(root_sig_deserializer.GetAddressOf()));
-	ERR_FAIL_COND_V_MSG(res, RID(), "D3D12CreateRootSignatureDeserializer failed with error " + vformat("0x%08ux", res) + ".");
-	read_offset += binary_data.root_signature_len;
-
-	ERR_FAIL_COND_V(read_offset != binsize, RID());
-
-	// TODO: Need to lock?
-	_THREAD_SAFE_METHOD_
-
-	ComPtr<ID3D12RootSignature> root_signature;
-	res = device->CreateRootSignature(0, root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(root_signature.GetAddressOf()));
-	ERR_FAIL_COND_V_MSG(res, RID(), "CreateRootSignature failed with error " + vformat("0x%08ux", res) + ".");
-
-	RID id;
-	if (p_placeholder.is_null()) {
-		id = shader_owner.make_rid();
-	} else {
-		id = p_placeholder;
-	}
-
-	Shader *shader = shader_owner.get_or_null(id);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	shader->vertex_input_mask = vertex_input_mask;
-	shader->fragment_output_mask = fragment_output_mask;
-	shader->spirv_push_constant_size = binary_data.push_constant_size;
-	shader->dxil_push_constant_size = binary_data.dxil_push_constant_stages ? binary_data.push_constant_size : 0;
-	shader->nir_runtime_data_root_param_idx = binary_data.nir_runtime_data_root_param_idx;
-	shader->is_compute = is_compute;
-	shader->compute_local_size[0] = compute_local_size[0];
-	shader->compute_local_size[1] = compute_local_size[1];
-	shader->compute_local_size[2] = compute_local_size[2];
-	shader->specialization_constants = specialization_constants;
-	shader->spirv_specialization_constants_ids_mask = binary_data.spirv_specialization_constants_ids_mask;
-	shader->name = name;
-	shader->root_signature = root_signature;
-	shader->root_signature_deserializer = root_sig_deserializer;
-	shader->root_signature_desc = root_sig_deserializer->GetRootSignatureDesc();
-	shader->root_signature_crc = binary_data.root_signature_crc;
-	shader->stages_bytecode = stages_bytecode;
-
-	// Proceed to create descriptor sets.
-	for (uint32_t i = 0; i < binary_data.set_count; i++) {
-		uint32_t format = 0; // No format, default.
-
-		Shader::Set &set = set_info.write[i];
-		if (set.uniforms.size()) {
-			// Has data, needs an actual format;.
-			UniformSetFormat usformat;
-			usformat.uniform_info.resize(set.uniforms.size());
-			for (int j = 0; j < set.uniforms.size(); j++) {
-				usformat.uniform_info.write[j] = set.uniforms[j].info;
-			}
-			RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);
-			if (E) {
-				format = E->get();
-			} else {
-				format = uniform_set_format_cache.size() + 1;
-				E = uniform_set_format_cache.insert(usformat, format);
-				uniform_set_format_cache_reverse.push_back(E);
-				DEV_ASSERT(uniform_set_format_cache_reverse.size() == uniform_set_format_cache.size());
-			}
-		}
-
-		shader->sets.push_back(set);
-		shader->set_formats.push_back(format);
-	}
-
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceD3D12::shader_create_placeholder() {
-	Shader shader;
-	return shader_owner.make_rid(shader);
-}
-
-uint64_t RenderingDeviceD3D12::shader_get_vertex_input_attribute_mask(RID p_shader) {
-	_THREAD_SAFE_METHOD_
-
-	const Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, 0);
-	return shader->vertex_input_mask;
-}
-
-/******************/
-/**** UNIFORMS ****/
-/******************/
-
-RID RenderingDeviceD3D12::uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	Buffer buffer;
-	Error err = _buffer_allocate(&buffer, p_size_bytes, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_HEAP_TYPE_DEFAULT);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-	}
-	RID id = uniform_buffer_owner.make_rid(buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceD3D12::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, BitField<StorageBufferUsage> p_usage) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	Buffer buffer;
-	D3D12_RESOURCE_STATES states = D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_COPY_DEST | D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-	if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {
-		states |= D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
-	}
-	Error err = _buffer_allocate(&buffer, p_size_bytes, states, D3D12_HEAP_TYPE_DEFAULT);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-	}
-	return storage_buffer_owner.make_rid(buffer);
-}
-
-RID RenderingDeviceD3D12::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	uint32_t element_size = get_format_vertex_size(p_format);
-	ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers");
-	uint64_t size_bytes = uint64_t(element_size) * p_size_elements;
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID());
-
-	TextureBuffer texture_buffer;
-	Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE, D3D12_HEAP_TYPE_DEFAULT);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&texture_buffer.buffer, 0, r, data_size);
-	}
-
-	// Allocate the view.
-	RID id = texture_buffer_owner.make_rid(texture_buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-Error RenderingDeviceD3D12::DescriptorsHeap::allocate(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type, uint32_t p_descriptor_count, bool p_for_gpu) {
-	ERR_FAIL_COND_V(heap, ERR_ALREADY_EXISTS);
-	ERR_FAIL_COND_V(p_descriptor_count == 0, ERR_INVALID_PARAMETER);
-
-	handle_size = p_device->GetDescriptorHandleIncrementSize(p_type);
-
-	desc.Type = p_type;
-	desc.NumDescriptors = p_descriptor_count;
-	desc.Flags = p_for_gpu ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
-	HRESULT res = p_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(heap.GetAddressOf()));
-	ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "CreateDescriptorHeap failed with error " + vformat("0x%08ux", res) + ".");
-
-	return OK;
-}
-
-RenderingDeviceD3D12::DescriptorsHeap::Walker RenderingDeviceD3D12::DescriptorsHeap::make_walker() const {
-	Walker walker;
-	walker.handle_size = handle_size;
-	walker.handle_count = desc.NumDescriptors;
-	if (heap) {
-		walker.first_cpu_handle = heap->GetCPUDescriptorHandleForHeapStart();
-		if ((desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
-			walker.first_gpu_handle = heap->GetGPUDescriptorHandleForHeapStart();
-		}
-	}
-	return walker;
-}
-
-void RenderingDeviceD3D12::DescriptorsHeap::Walker::advance(uint32_t p_count) {
-	ERR_FAIL_COND_MSG(handle_index + p_count > handle_count, "Would advance past EOF.");
-	handle_index += p_count;
-}
-
-D3D12_CPU_DESCRIPTOR_HANDLE RenderingDeviceD3D12::DescriptorsHeap::Walker::get_curr_cpu_handle() {
-	ERR_FAIL_COND_V_MSG(is_at_eof(), D3D12_CPU_DESCRIPTOR_HANDLE(), "Heap walker is at EOF.");
-	return D3D12_CPU_DESCRIPTOR_HANDLE{ first_cpu_handle.ptr + handle_index * handle_size };
-}
-
-D3D12_GPU_DESCRIPTOR_HANDLE RenderingDeviceD3D12::DescriptorsHeap::Walker::get_curr_gpu_handle() {
-	ERR_FAIL_COND_V_MSG(!first_gpu_handle.ptr, D3D12_GPU_DESCRIPTOR_HANDLE(), "Can't provide a GPU handle from a non-GPU descriptors heap.");
-	ERR_FAIL_COND_V_MSG(is_at_eof(), D3D12_GPU_DESCRIPTOR_HANDLE(), "Heap walker is at EOF.");
-	return D3D12_GPU_DESCRIPTOR_HANDLE{ first_gpu_handle.ptr + handle_index * handle_size };
-}
-
-static void _add_descriptor_count_for_uniform(RenderingDevice::UniformType p_type, uint32_t p_binding_length, bool p_dobule_srv_uav_ambiguous, uint32_t &r_num_resources, uint32_t &r_num_samplers, bool &r_srv_uav_ambiguity) {
-	r_srv_uav_ambiguity = false;
-
-	// Some resource types can be SRV or UAV, depending on what NIR-DXIL decided for a specific shader variant.
-	// The goal is to generate both SRV and UAV for the descriptor sets' heaps and copy only the relevant one
-	// to the frame descriptor heap at binding time.
-	// [[SRV_UAV_AMBIGUITY]]
-
-	switch (p_type) {
-		case RenderingDevice::UNIFORM_TYPE_SAMPLER: {
-			r_num_samplers += p_binding_length;
-		} break;
-		case RenderingDevice::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE:
-		case RenderingDevice::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
-			r_num_resources += p_binding_length;
-			r_num_samplers += p_binding_length;
-		} break;
-		case RenderingDevice::UNIFORM_TYPE_UNIFORM_BUFFER: {
-			r_num_resources += 1;
-		} break;
-		case RenderingDevice::UNIFORM_TYPE_STORAGE_BUFFER: {
-			r_num_resources += p_dobule_srv_uav_ambiguous ? 2 : 1;
-			r_srv_uav_ambiguity = true;
-		} break;
-		case RenderingDevice::UNIFORM_TYPE_IMAGE: {
-			r_num_resources += p_binding_length * (p_dobule_srv_uav_ambiguous ? 2 : 1);
-			r_srv_uav_ambiguity = true;
-		} break;
-		default: {
-			r_num_resources += p_binding_length;
-		}
-	}
-}
-
-RID RenderingDeviceD3D12::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_uniforms.size() == 0, RID());
-
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniforms.size() == 0, RID(),
-			"Desired set (" + itos(p_shader_set) + ") not used by shader.");
-	// See that all sets in shader are satisfied.
-
-	const Shader::Set &set = shader->sets[p_shader_set];
-
-	uint32_t uniform_count = p_uniforms.size();
-	const Uniform *uniforms = p_uniforms.ptr();
-
-	uint32_t set_uniform_count = set.uniforms.size();
-	const Shader::ShaderUniformInfo *set_uniforms = set.uniforms.ptr();
-
-	// Do a first pass to count resources and samplers, and error checking.
-	uint32_t num_resource_descs = 0;
-	uint32_t num_sampler_descs = 0;
-	LocalVector<int> uniform_indices;
-	uniform_indices.resize(set_uniform_count);
-	for (uint32_t i = 0; i < set_uniform_count; i++) {
-		const UniformInfo &set_uniform = set_uniforms[i].info;
-		int uniform_idx = -1;
-		for (int j = 0; j < (int)uniform_count; j++) {
-			if (uniforms[j].binding == set_uniform.binding) {
-				uniform_idx = j;
-			}
-		}
-		ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(),
-				"All the shader bindings for the given set must be covered by the uniforms provided. Binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + ") was not provided.");
-		uniform_indices[i] = uniform_idx;
-
-		const Uniform &uniform = uniforms[uniform_idx];
-		ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(),
-				"Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'.");
-
-		// Since the uniform set may be created for a shader different than the one that will be actually bound,
-		// which may have a different set of uniforms optimized out, the stages mask we can check now is not reliable.
-		// Therefore, we can't make any assumptions here about descriptors that we may not need to create,
-		// pixel or vertex-only shader resource states, etc.
-
-		bool srv_uav_ambiguity = false;
-		_add_descriptor_count_for_uniform(uniform.uniform_type, set_uniform.length, true, num_resource_descs, num_sampler_descs, srv_uav_ambiguity);
-	}
-
-	struct {
-		DescriptorsHeap resources;
-		DescriptorsHeap samplers;
-	} desc_heaps;
-#ifdef DEV_ENABLED
-	LocalVector<UniformSet::ResourceDescInfo> resources_desc_info;
-#endif
-
-	if (num_resource_descs) {
-		Error err = desc_heaps.resources.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, num_resource_descs, false);
-		ERR_FAIL_COND_V(err, RID());
-	}
-	if (num_sampler_descs) {
-		Error err = desc_heaps.samplers.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_sampler_descs, false);
-		ERR_FAIL_COND_V(err, RID());
-	}
-	struct {
-		DescriptorsHeap::Walker resources;
-		DescriptorsHeap::Walker samplers;
-	} desc_heap_walkers;
-	desc_heap_walkers.resources = desc_heaps.resources.make_walker();
-	desc_heap_walkers.samplers = desc_heaps.samplers.make_walker();
-
-	// Used for verification to make sure a uniform set does not use a framebuffer bound texture.
-	LocalVector<UniformSet::AttachableTexture> attachable_textures;
-	struct RIDState {
-		bool is_buffer = false;
-		uint64_t shader_uniform_idx_mask = 0;
-		ResourceState state;
-	};
-	HashMap<Resource *, RIDState> resource_states;
-
-	for (uint32_t i = 0; i < set_uniform_count; i++) {
-		const Shader::ShaderUniformInfo &set_uniform = set_uniforms[i];
-		const Uniform &uniform = uniforms[uniform_indices[i]];
-
-		// Stages defined in the shader may be missing for a uniform due to the optimizer,
-		// but the opposite (extraneous stages present in the uniform stages mask) would be an error.
-		DEV_ASSERT(!(shader->is_compute && (set_uniform.binding.stages & (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT))));
-		DEV_ASSERT(!(!shader->is_compute && (set_uniform.binding.stages & SHADER_STAGE_COMPUTE_BIT)));
-
-		switch (uniform.uniform_type) {
-			case UNIFORM_TYPE_SAMPLER: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					D3D12_SAMPLER_DESC *sampler_desc = sampler_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_COND_V_MSG(!sampler_desc, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
-
-					device->CreateSampler(sampler_desc, desc_heap_walkers.samplers.get_curr_cpu_handle());
-					desc_heap_walkers.samplers.advance();
-				}
-			} break;
-			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length * 2) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
-					D3D12_SAMPLER_DESC *sampler_desc = sampler_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_COND_V_MSG(!sampler_desc, RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
-
-					RID rid = uniform.get_id(j + 1);
-					Texture *texture = texture_owner.get_or_null(rid);
-					ERR_FAIL_COND_V_MSG(!texture, RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					device->CreateSampler(sampler_desc, desc_heap_walkers.samplers.get_curr_cpu_handle());
-					desc_heap_walkers.samplers.advance();
-					device->CreateShaderResourceView(texture->resource, &texture->srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture->srv_desc.ViewDimension });
-#endif
-					desc_heap_walkers.resources.advance();
-
-					RIDState &rs = resource_states[texture];
-					rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-					rs.state.extend(D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);
-
-					if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
-						UniformSet::AttachableTexture attachable_texture;
-						attachable_texture.bind = set_uniform.info.binding;
-						attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1);
-						attachable_textures.push_back(attachable_texture);
-					}
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-				}
-			} break;
-			case UNIFORM_TYPE_TEXTURE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					RID rid = uniform.get_id(j);
-					Texture *texture = texture_owner.get_or_null(rid);
-					ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					device->CreateShaderResourceView(texture->resource, &texture->srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture->srv_desc.ViewDimension });
-#endif
-					desc_heap_walkers.resources.advance();
-
-					RIDState &rs = resource_states[texture];
-					rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-					rs.state.extend(D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);
-
-					if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) {
-						UniformSet::AttachableTexture attachable_texture;
-						attachable_texture.bind = set_uniform.info.binding;
-						attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j);
-						attachable_textures.push_back(attachable_texture);
-					}
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-				}
-			} break;
-			case UNIFORM_TYPE_IMAGE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					RID rid = uniform.get_id(j);
-					Texture *texture = texture_owner.get_or_null(rid);
-
-					ERR_FAIL_COND_V_MSG(!texture, RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
-
-					RIDState &rs = resource_states[texture];
-					rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-					rs.state.extend(D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
-				}
-
-				// SRVs first. [[SRV_UAV_AMBIGUITY]]
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					RID rid = uniform.get_id(j);
-					Texture *texture = texture_owner.get_or_null(rid);
-
-					ERR_FAIL_COND_V_MSG(!texture, RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
-
-					device->CreateShaderResourceView(texture->resource, &texture->srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture->srv_desc.ViewDimension });
-#endif
-					desc_heap_walkers.resources.advance();
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-				}
-
-				// UAVs then. [[SRV_UAV_AMBIGUITY]]
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					RID rid = uniform.get_id(j);
-					Texture *texture = texture_owner.get_or_null(rid);
-
-					device->CreateUnorderedAccessView(texture->resource, nullptr, &texture->uav_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_UAV, {} });
-#endif
-					desc_heap_walkers.resources.advance();
-				}
-			} break;
-			case UNIFORM_TYPE_TEXTURE_BUFFER: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_COND_V_MSG(!buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
-
-					CRASH_NOW_MSG("Unimplemented!");
-				}
-			} break;
-			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
-				CRASH_NOW();
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length * 2) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
-					D3D12_SAMPLER_DESC *sampler_desc = sampler_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_COND_V_MSG(!sampler_desc, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
-
-					TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
-					ERR_FAIL_COND_V_MSG(!buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
-
-					device->CreateSampler(sampler_desc, desc_heap_walkers.samplers.get_curr_cpu_handle());
-					desc_heap_walkers.samplers.advance();
-
-					CRASH_NOW_MSG("Unimplemented!");
-				}
-			} break;
-			case UNIFORM_TYPE_IMAGE_BUFFER: {
-				// Todo.
-
-			} break;
-			case UNIFORM_TYPE_UNIFORM_BUFFER: {
-				ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
-						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
-
-				RID rid = uniform.get_id(0);
-				Buffer *buffer = uniform_buffer_owner.get_or_null(rid);
-				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
-
-				ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.info.length, RID(),
-						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " is smaller than size of shader uniform: (" + itos(set_uniform.info.length) + ").");
-
-				D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {};
-				cbv_desc.BufferLocation = buffer->resource->GetGPUVirtualAddress();
-				cbv_desc.SizeInBytes = ALIGN(buffer->size, 256);
-				device->CreateConstantBufferView(&cbv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-				desc_heap_walkers.resources.advance();
-#ifdef DEV_ENABLED
-				resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_CBV, {} });
-#endif
-
-				RIDState &rs = resource_states[buffer];
-				rs.is_buffer = true;
-				rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-				rs.state.extend(D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
-			} break;
-			case UNIFORM_TYPE_STORAGE_BUFFER: {
-				ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
-						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
-
-				RID rid = uniform.get_id(0);
-				Buffer *buffer = nullptr;
-
-				if (storage_buffer_owner.owns(rid)) {
-					buffer = storage_buffer_owner.get_or_null(rid);
-				} else if (vertex_buffer_owner.owns(rid)) {
-					buffer = vertex_buffer_owner.get_or_null(rid);
-					// Due to [[SRV_UAV_AMBIGUITY]] we can't make this check because it wouldn't make sense in the case of an SRV (r/o storage buffer).
-					//ERR_FAIL_COND_V_MSG(!(buffer->usage & D3D12_RESOURCE_STATE_UNORDERED_ACCESS), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");
-				}
-				ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
-
-				// If 0, then it's sized at link time.
-				ERR_FAIL_COND_V_MSG(set_uniform.info.length > 0 && buffer->size != (uint32_t)set_uniform.info.length, RID(),
-						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.info.length) + ").");
-
-				RIDState &rs = resource_states[buffer];
-				rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-				rs.is_buffer = true;
-				rs.state.extend(D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
-
-				// SRV first. [[SRV_UAV_AMBIGUITY]]
-				{
-					D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
-					srv_desc.Format = DXGI_FORMAT_R32_TYPELESS;
-					srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
-					srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-					srv_desc.Buffer.FirstElement = 0;
-					srv_desc.Buffer.NumElements = (buffer->size + 3) / 4;
-					srv_desc.Buffer.StructureByteStride = 0;
-					srv_desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
-					device->CreateShaderResourceView(buffer->resource, &srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, srv_desc.ViewDimension });
-#endif
-					desc_heap_walkers.resources.advance();
-				}
-
-				// UAV then. [[SRV_UAV_AMBIGUITY]]
-				{
-					if ((buffer->usage & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
-						D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
-						uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
-						uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
-						uav_desc.Buffer.FirstElement = 0;
-						uav_desc.Buffer.NumElements = (buffer->size + 3) / 4;
-						uav_desc.Buffer.StructureByteStride = 0;
-						uav_desc.Buffer.CounterOffsetInBytes = 0;
-						uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
-						device->CreateUnorderedAccessView(buffer->resource, nullptr, &uav_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-						resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_UAV, {} });
-#endif
-					} else {
-						// If can't transition to UAV, leave this one empty since it won't be
-						// used, and trying to create an UAV view would trigger a validation error.
-					}
-
-					desc_heap_walkers.resources.advance();
-				}
-			} break;
-			case UNIFORM_TYPE_INPUT_ATTACHMENT: {
-				ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");
-
-				if (uniform.get_id_count() != (uint32_t)set_uniform.info.length) {
-					if (set_uniform.info.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.info.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					RID rid = uniform.get_id(j);
-					Texture *texture = texture_owner.get_or_null(rid);
-					ERR_FAIL_COND_V_MSG(!texture, RID(),
-							"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					device->CreateShaderResourceView(texture->resource, &texture->srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
-#ifdef DEV_ENABLED
-					resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture->srv_desc.ViewDimension });
-#endif
-					desc_heap_walkers.resources.advance();
-
-					RIDState &rs = resource_states[texture];
-					rs.shader_uniform_idx_mask |= ((uint64_t)1 << i);
-					rs.state.extend(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-				}
-			} break;
-			default: {
-			}
-		}
-	}
-
-	DEV_ASSERT(desc_heap_walkers.resources.is_at_eof());
-	DEV_ASSERT(desc_heap_walkers.samplers.is_at_eof());
-
-	UniformSet uniform_set;
-	uniform_set.desc_heaps.resources = desc_heaps.resources;
-	uniform_set.desc_heaps.samplers = desc_heaps.samplers;
-	uniform_set.format = shader->set_formats[p_shader_set];
-	uniform_set.attachable_textures = attachable_textures;
-	uniform_set.shader_set = p_shader_set;
-	uniform_set.shader_id = p_shader;
-#ifdef DEV_ENABLED
-	uniform_set._resources_desc_info = resources_desc_info;
-	uniform_set._shader = shader;
-#endif
-
-	{
-		uniform_set.resource_states.resize(resource_states.size());
-		uint32_t i = 0;
-		for (const KeyValue<Resource *, RIDState> &E : resource_states) {
-			UniformSet::StateRequirement sr;
-			sr.resource = E.key;
-			sr.is_buffer = E.value.is_buffer;
-			sr.states = E.value.state.get_state_mask();
-			sr.shader_uniform_idx_mask = E.value.shader_uniform_idx_mask;
-			uniform_set.resource_states.write[i] = sr;
-			i++;
-		}
-	}
-
-	RID id = uniform_set_owner.make_rid(uniform_set);
-	// Add dependencies.
-	_add_dependency(id, p_shader);
-	for (uint32_t i = 0; i < uniform_count; i++) {
-		const Uniform &uniform = uniforms[i];
-		int id_count = uniform.get_id_count();
-		for (int j = 0; j < id_count; j++) {
-			_add_dependency(id, uniform.get_id(j));
-		}
-	}
-
-	return id;
-}
-
-bool RenderingDeviceD3D12::uniform_set_is_valid(RID p_uniform_set) {
-	return uniform_set_owner.owns(p_uniform_set);
-}
-
-void RenderingDeviceD3D12::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {
-	UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(us);
-	us->invalidated_callback = p_callback;
-	us->invalidated_callback_userdata = p_userdata;
-}
-
-Error RenderingDeviceD3D12::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Copying buffers is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Copying buffers is forbidden during creation of a compute list");
-
-	Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer);
-	if (!src_buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");
-	}
-
-	Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer);
-	if (!dst_buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");
-	}
-
-	// Validate the copy's dimensions for both buffers.
-	ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer.");
-	ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer.");
-
-	// Perform the copy.
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	_resource_transition_batch(src_buffer, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
-	_resource_transition_batch(src_buffer, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
-	_resource_transitions_flush(command_list);
-
-	command_list->CopyBufferRegion(dst_buffer->resource, p_dst_offset, src_buffer->resource, p_src_offset, p_size);
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a compute list");
-
-	Buffer *buffer = _get_buffer_from_owner(p_buffer);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
-	}
-
-	ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
-			"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	_resource_transition_batch(buffer, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
-	_resource_transitions_flush(command_list);
-
-	Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier);
-	if (err) {
-		return err;
-	}
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
-			"Size must be a multiple of four");
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Updating buffers in is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a compute list");
-
-	Buffer *buffer = _get_buffer_from_owner(p_buffer);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
-	}
-
-	ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
-			"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
-
-	if (frames[frame].desc_heap_walkers.resources.is_at_eof()) {
-		if (!frames[frame].desc_heaps_exhausted_reported.resources) {
-			frames[frame].desc_heaps_exhausted_reported.resources = true;
-			ERR_FAIL_V_MSG(ERR_BUSY,
-					"Cannot clear buffer because there's no enough room in current frame's RESOURCE descriptors heap.\n"
-					"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
-		} else {
-			return ERR_BUSY;
-		}
-	}
-	if (frames[frame].desc_heap_walkers.aux.is_at_eof()) {
-		if (!frames[frame].desc_heaps_exhausted_reported.aux) {
-			frames[frame].desc_heaps_exhausted_reported.aux = true;
-			ERR_FAIL_V_MSG(ERR_BUSY,
-					"Cannot clear buffer because there's no enough room in current frame's AUX descriptors heap.\n"
-					"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
-		} else {
-			return ERR_BUSY;
-		}
-	}
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	_resource_transition_batch(buffer, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
-	_resource_transitions_flush(command_list);
-
-	D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
-	uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
-	uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
-	uav_desc.Buffer.FirstElement = 0;
-	uav_desc.Buffer.NumElements = (buffer->size + 3) / 4;
-	uav_desc.Buffer.StructureByteStride = 0;
-	uav_desc.Buffer.CounterOffsetInBytes = 0;
-	uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
-	device->CreateUnorderedAccessView(
-			buffer->resource,
-			nullptr,
-			&uav_desc,
-			frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle());
-
-	device->CopyDescriptorsSimple(
-			1,
-			frames[frame].desc_heap_walkers.resources.get_curr_cpu_handle(),
-			frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle(),
-			D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
-
-	static const UINT values[4] = {};
-	command_list->ClearUnorderedAccessViewUint(
-			frames[frame].desc_heap_walkers.resources.get_curr_gpu_handle(),
-			frames[frame].desc_heap_walkers.aux.get_curr_cpu_handle(),
-			buffer->resource,
-			values,
-			0,
-			nullptr);
-
-	frames[frame].desc_heap_walkers.resources.advance();
-	frames[frame].desc_heap_walkers.aux.advance();
-
-	return OK;
-}
-
-Vector<uint8_t> RenderingDeviceD3D12::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) {
-	_THREAD_SAFE_METHOD_
-
-	// Get the vulkan buffer and the potential stage/access possible.
-	Buffer *buffer = _get_buffer_from_owner(p_buffer);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
-	}
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	// Size of buffer to retrieve.
-	if (!p_size) {
-		p_size = buffer->size;
-	} else {
-		ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(),
-				"Size is larger than the buffer.");
-	}
-
-	_resource_transition_batch(buffer, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
-	_resource_transitions_flush(command_list);
-
-	Buffer tmp_buffer;
-	Error err = _buffer_allocate(&tmp_buffer, p_size, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_HEAP_TYPE_READBACK);
-	ERR_FAIL_COND_V(err != OK, Vector<uint8_t>());
-
-	command_list->CopyBufferRegion(tmp_buffer.resource, 0, buffer->resource, p_offset, p_size);
-
-	// Flush everything so memory can be safely mapped.
-	_flush(true);
-
-	void *buffer_mem;
-	HRESULT res = tmp_buffer.resource->Map(0, &VOID_RANGE, &buffer_mem);
-	ERR_FAIL_COND_V_MSG(res, Vector<uint8_t>(), "Map failed with error " + vformat("0x%08ux", res) + ".");
-
-	Vector<uint8_t> buffer_data;
-	{
-		buffer_data.resize(buffer->size);
-		uint8_t *w = buffer_data.ptrw();
-		memcpy(w, buffer_mem, buffer->size);
-	}
-
-	tmp_buffer.resource->Unmap(0, &VOID_RANGE);
-
-	_buffer_free(&tmp_buffer);
-
-	return buffer_data;
-}
-
-/*******************/
-/**** PIPELINES ****/
-/*******************/
-
-Error RenderingDeviceD3D12::_apply_specialization_constants(
-		const Shader *p_shader,
-		const Vector<PipelineSpecializationConstant> &p_specialization_constants,
-		HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode) {
-	// If something needs to be patched, COW will do the trick.
-	r_final_stages_bytecode = p_shader->stages_bytecode;
-	uint32_t stages_re_sign_mask = 0;
-	for (const PipelineSpecializationConstant &psc : p_specialization_constants) {
-		if (!(p_shader->spirv_specialization_constants_ids_mask & (1 << psc.constant_id))) {
-			// This SC wasn't even in the original SPIR-V shader.
-			continue;
-		}
-		for (const Shader::SpecializationConstant &sc : p_shader->specialization_constants) {
-			if (psc.constant_id == sc.constant.constant_id) {
-				ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, ERR_INVALID_PARAMETER, "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
-				if (psc.int_value != sc.constant.int_value) {
-					stages_re_sign_mask |= _shader_patch_dxil_specialization_constant(psc.type, &psc.int_value, sc.stages_bit_offsets, r_final_stages_bytecode, false);
-				}
-				break;
-			}
-		}
-	}
-	// Re-sign patched stages.
-	for (KeyValue<ShaderStage, Vector<uint8_t>> &E : r_final_stages_bytecode) {
-		ShaderStage stage = E.key;
-		if ((stages_re_sign_mask & (1 << stage))) {
-			Vector<uint8_t> &bytecode = E.value;
-			bool sign_ok = _shader_sign_dxil_bytecode(stage, bytecode);
-			ERR_FAIL_COND_V(!sign_ok, ERR_QUERY_FAILED);
-		}
-	}
-
-	return OK;
-}
-
-#ifdef DEV_ENABLED
-String RenderingDeviceD3D12::_build_pipeline_blob_filename(
-		const Vector<uint8_t> &p_blob,
-		const Shader *p_shader,
-		const Vector<PipelineSpecializationConstant> &p_specialization_constants,
-		const String &p_extra_name_suffix,
-		const String &p_forced_id) {
-	String id;
-	if (p_forced_id == "") {
-		HashingContext hc;
-		hc.start(HashingContext::HASH_MD5);
-		hc.update(p_blob);
-		Vector<uint8_t> hash_bin = hc.finish();
-		String hash_str = String::hex_encode_buffer(hash_bin.ptr(), hash_bin.size());
-	} else {
-		id = p_forced_id;
-	}
-
-	Vector<String> sc_str_pieces;
-	for (const Shader::SpecializationConstant &sc : p_shader->specialization_constants) {
-		uint32_t int_value = sc.constant.int_value;
-		for (const PipelineSpecializationConstant &psc : p_specialization_constants) {
-			if (psc.constant_id == sc.constant.constant_id) {
-				int_value = psc.int_value;
-				break;
-			}
-		}
-		sc_str_pieces.push_back(itos(sc.constant.constant_id) + "=" + itos(int_value));
-	}
-
-	String res = p_shader->name.replace(":", "-");
-	res += "." + id;
-	res += "." + String("_").join(sc_str_pieces);
-	if (p_extra_name_suffix != "") {
-		res += "." + p_extra_name_suffix;
-	}
-	return res;
-}
-
-void RenderingDeviceD3D12::_save_pso_blob(
-		ID3D12PipelineState *p_pso,
-		const Shader *p_shader,
-		const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-	ComPtr<ID3DBlob> pso_blob;
-	p_pso->GetCachedBlob(pso_blob.GetAddressOf());
-	Vector<uint8_t> pso_vector;
-	pso_vector.resize(pso_blob->GetBufferSize());
-	memcpy(pso_vector.ptrw(), pso_blob->GetBufferPointer(), pso_blob->GetBufferSize());
-
-	String base_filename = _build_pipeline_blob_filename(pso_vector, p_shader, p_specialization_constants);
-
-	Ref<FileAccess> fa = FileAccess::open("pso." + base_filename + ".bin", FileAccess::WRITE);
-	fa->store_buffer((const uint8_t *)pso_blob->GetBufferPointer(), pso_blob->GetBufferSize());
-}
-
-void RenderingDeviceD3D12::_save_stages_bytecode(
-		const HashMap<ShaderStage, Vector<uint8_t>> &p_stages_bytecode,
-		const Shader *p_shader,
-		const RID p_shader_rid,
-		const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-	for (const KeyValue<ShaderStage, Vector<uint8_t>> &E : p_stages_bytecode) {
-		ShaderStage stage = E.key;
-		const Vector<uint8_t> &bytecode = E.value;
-
-		String base_filename = _build_pipeline_blob_filename(bytecode, p_shader, p_specialization_constants, shader_stage_names[stage], itos(p_shader_rid.get_id()));
-
-		Ref<FileAccess> fa = FileAccess::open("dxil." + base_filename + ".bin", FileAccess::WRITE);
-		fa->store_buffer(bytecode.ptr(), bytecode.size());
-	}
-}
-#endif
-
-/*************************/
-/**** RENDER PIPELINE ****/
-/*************************/
-
-RID RenderingDeviceD3D12::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-#ifdef DEV_ENABLED
-//#define DEBUG_CREATE_DEBUG_PSO
-//#define DEBUG_SAVE_PSO_BLOBS
-//#define DEBUG_SAVE_DXIL_BLOBS
-#endif
-	_THREAD_SAFE_METHOD_
-
-	// Needs a shader.
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(shader->is_compute, RID(),
-			"Compute shaders can't be used in render pipelines");
-
-	if (p_framebuffer_format == INVALID_ID) {
-		// If nothing provided, use an empty one (no attachments).
-		p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());
-	}
-	ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());
-	const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format];
-	const FramebufferPass &pass = fb_format.passes[p_for_render_pass];
-
-	{ // Validate shader vs framebuffer.
-
-		ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds");
-		uint32_t output_mask = 0;
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) {
-				output_mask |= 1 << i;
-			}
-		}
-		ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),
-				"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");
-	}
-
-	CD3DX12_PIPELINE_STATE_STREAM pipeline_desc;
-	RenderPipeline::DynamicParams dyn_params;
-
-	// Attachment formats.
-	{
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			int32_t attachment = pass.color_attachments[i];
-			if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-				(&pipeline_desc.RTVFormats)->RTFormats[i] = DXGI_FORMAT_UNKNOWN;
-			} else {
-				(&pipeline_desc.RTVFormats)->RTFormats[i] = d3d12_formats[fb_format.attachments[attachment].format].general_format;
-			}
-		}
-		(&pipeline_desc.RTVFormats)->NumRenderTargets = pass.color_attachments.size();
-
-		if (pass.depth_attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-			pipeline_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
-		} else {
-			pipeline_desc.DSVFormat = d3d12_formats[fb_format.attachments[pass.depth_attachment].format].dsv_format;
-		}
-	}
-
-	// Vertex.
-	if (p_vertex_format != INVALID_ID) {
-		// Uses vertices, else it does not.
-		ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
-		const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
-
-		(&pipeline_desc.InputLayout)->pInputElementDescs = vd.elements_desc.ptr();
-		(&pipeline_desc.InputLayout)->NumElements = vd.elements_desc.size();
-
-		// Validate with inputs.
-		for (uint32_t i = 0; i < 64; i++) {
-			if (!(shader->vertex_input_mask & (1ULL << i))) {
-				continue;
-			}
-			bool found = false;
-			for (int j = 0; j < vd.vertex_formats.size(); j++) {
-				if (vd.vertex_formats[j].location == i) {
-					found = true;
-				}
-			}
-
-			ERR_FAIL_COND_V_MSG(!found, RID(),
-					"Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation.");
-		}
-
-	} else {
-		// Does not use vertices.
-
-		ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),
-				"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");
-	}
-
-	// Input assembly & tessellation.
-
-	ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());
-
-	static const D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_types[RENDER_PRIMITIVE_MAX] = {
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
-		D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
-	};
-
-	static const D3D12_PRIMITIVE_TOPOLOGY topologies[RENDER_PRIMITIVE_MAX] = {
-		D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
-		D3D_PRIMITIVE_TOPOLOGY_LINELIST,
-		D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
-		D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
-		D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
-		D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
-		D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
-		D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
-		D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
-		D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
-		D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
-	};
-
-	pipeline_desc.PrimitiveTopologyType = topology_types[p_render_primitive];
-	if (p_render_primitive == RENDER_PRIMITIVE_TESSELATION_PATCH) {
-		ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > 32, RID()); // Is there any way to get the true point count limit?
-		dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);
-	} else {
-		dyn_params.primitive_topology = topologies[p_render_primitive];
-	}
-	if (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX) {
-		// TODO: This is right for 16-bit indices; for 32-bit there's a different enum value to set, but we don't know at this point.
-		pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
-	} else {
-		pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
-	}
-
-	// Rasterization.
-	(&pipeline_desc.RasterizerState)->DepthClipEnable = !p_rasterization_state.enable_depth_clamp;
-	// In D3D12, discard can be supported with some extra effort (empty pixel shader + disable depth/stencil test); that said, unsupported by now.
-	ERR_FAIL_COND_V(p_rasterization_state.discard_primitives, RID());
-	(&pipeline_desc.RasterizerState)->FillMode = p_rasterization_state.wireframe ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
-	static const D3D12_CULL_MODE cull_mode[3] = {
-		D3D12_CULL_MODE_NONE,
-		D3D12_CULL_MODE_FRONT,
-		D3D12_CULL_MODE_BACK,
-	};
-
-	ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());
-	(&pipeline_desc.RasterizerState)->CullMode = cull_mode[p_rasterization_state.cull_mode];
-	(&pipeline_desc.RasterizerState)->FrontCounterClockwise = p_rasterization_state.front_face == POLYGON_FRONT_FACE_COUNTER_CLOCKWISE;
-	// In D3D12, there's still a point in setting up depth bias with no depth buffer, but just zeroing (disabling) it all in such case is closer to Vulkan.
-	if (p_rasterization_state.depth_bias_enabled && fb_format.passes[p_for_render_pass].depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-		(&pipeline_desc.RasterizerState)->DepthBias = p_rasterization_state.depth_bias_constant_factor;
-		(&pipeline_desc.RasterizerState)->DepthBiasClamp = p_rasterization_state.depth_bias_clamp;
-		(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = p_rasterization_state.depth_bias_slope_factor;
-	} else {
-		(&pipeline_desc.RasterizerState)->DepthBias = 0;
-		(&pipeline_desc.RasterizerState)->DepthBiasClamp = 0.0f;
-		(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = 0.0f;
-	}
-
-	(&pipeline_desc.RasterizerState)->ForcedSampleCount = 0;
-	(&pipeline_desc.RasterizerState)->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
-	(&pipeline_desc.RasterizerState)->MultisampleEnable = rasterization_sample_count[p_multisample_state.sample_count] != 1;
-	(&pipeline_desc.RasterizerState)->AntialiasedLineEnable = true;
-
-	// In D3D12, there's no line width.
-	ERR_FAIL_COND_V(!Math::is_equal_approx(p_rasterization_state.line_width, 1.0f), RID());
-
-	// Multisample.
-	ERR_FAIL_COND_V(p_multisample_state.enable_sample_shading, RID()); // How one enables this in D3D12?
-	if ((&pipeline_desc.RTVFormats)->NumRenderTargets || pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {
-		uint32_t sample_count = MIN(
-				fb_format.max_supported_sample_count,
-				rasterization_sample_count[p_multisample_state.sample_count]);
-		(&pipeline_desc.SampleDesc)->Count = sample_count;
-	} else {
-		(&pipeline_desc.SampleDesc)->Count = 1;
-	}
-	if ((&pipeline_desc.SampleDesc)->Count > 1) {
-		(&pipeline_desc.SampleDesc)->Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
-	} else {
-		(&pipeline_desc.SampleDesc)->Quality = 0;
-	}
-	if (p_multisample_state.sample_mask.size()) {
-		// Use sample mask.
-		ERR_FAIL_COND_V(rasterization_sample_count[p_multisample_state.sample_count] != (uint32_t)p_multisample_state.sample_mask.size(), RID());
-		for (int i = 1; i < p_multisample_state.sample_mask.size(); i++) {
-			// In D3D12 there's a single sample mask for every pixel.
-			ERR_FAIL_COND_V(p_multisample_state.sample_mask[i] != p_multisample_state.sample_mask[0], RID());
-		}
-		pipeline_desc.SampleMask = p_multisample_state.sample_mask[0];
-	} else {
-		pipeline_desc.SampleMask = 0xffffffff;
-	}
-
-	// Depth stencil.
-
-	if (pass.depth_attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-		(&pipeline_desc.DepthStencilState)->DepthEnable = false;
-		(&pipeline_desc.DepthStencilState)->StencilEnable = false;
-	} else {
-		(&pipeline_desc.DepthStencilState)->DepthEnable = p_depth_stencil_state.enable_depth_test;
-		(&pipeline_desc.DepthStencilState)->DepthWriteMask = p_depth_stencil_state.enable_depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->DepthFunc = compare_operators[p_depth_stencil_state.depth_compare_operator];
-		(&pipeline_desc.DepthStencilState)->DepthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;
-		(&pipeline_desc.DepthStencilState)->StencilEnable = p_depth_stencil_state.enable_stencil;
-
-		// In D3D12 some elements can't be different across front and back.
-		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.compare_mask != p_depth_stencil_state.back_op.compare_mask, RID());
-		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.write_mask != p_depth_stencil_state.back_op.write_mask, RID());
-		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.reference != p_depth_stencil_state.back_op.reference, RID());
-		(&pipeline_desc.DepthStencilState)->StencilReadMask = p_depth_stencil_state.front_op.compare_mask;
-		(&pipeline_desc.DepthStencilState)->StencilWriteMask = p_depth_stencil_state.front_op.write_mask;
-
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->FrontFace.StencilFailOp = stencil_operations[p_depth_stencil_state.front_op.fail];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->FrontFace.StencilPassOp = stencil_operations[p_depth_stencil_state.front_op.pass];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->FrontFace.StencilDepthFailOp = stencil_operations[p_depth_stencil_state.front_op.depth_fail];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->FrontFace.StencilFunc = compare_operators[p_depth_stencil_state.front_op.compare];
-
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->BackFace.StencilFailOp = stencil_operations[p_depth_stencil_state.back_op.fail];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->BackFace.StencilPassOp = stencil_operations[p_depth_stencil_state.back_op.pass];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->BackFace.StencilDepthFailOp = stencil_operations[p_depth_stencil_state.back_op.depth_fail];
-		ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID());
-		(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = compare_operators[p_depth_stencil_state.back_op.compare];
-
-		dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
-		dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
-		dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
-	}
-
-	// Blend state.
-	(&pipeline_desc.BlendState)->AlphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
-	{
-		ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());
-
-		bool all_attachments_same_blend = true;
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			const PipelineColorBlendState::Attachment &bs = p_blend_state.attachments[i];
-			D3D12_RENDER_TARGET_BLEND_DESC &bd = (&pipeline_desc.BlendState)->RenderTarget[i];
-
-			bd.BlendEnable = bs.enable_blend;
-			bd.LogicOpEnable = p_blend_state.enable_logic_op;
-			bd.LogicOp = logic_operations[p_blend_state.logic_op];
-
-			ERR_FAIL_INDEX_V(bs.src_color_blend_factor, BLEND_FACTOR_MAX, RID());
-			bd.SrcBlend = blend_factors[bs.src_color_blend_factor];
-			ERR_FAIL_INDEX_V(bs.dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
-			bd.DestBlend = blend_factors[bs.dst_color_blend_factor];
-			ERR_FAIL_INDEX_V(bs.color_blend_op, BLEND_OP_MAX, RID());
-			bd.BlendOp = blend_operations[bs.color_blend_op];
-
-			ERR_FAIL_INDEX_V(bs.src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
-			bd.SrcBlendAlpha = blend_factors[bs.src_alpha_blend_factor];
-			ERR_FAIL_INDEX_V(bs.dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
-			bd.DestBlendAlpha = blend_factors[bs.dst_alpha_blend_factor];
-			ERR_FAIL_INDEX_V(bs.alpha_blend_op, BLEND_OP_MAX, RID());
-			bd.BlendOpAlpha = blend_operations[bs.alpha_blend_op];
-
-			if (bs.write_r) {
-				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED;
-			}
-			if (bs.write_g) {
-				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN;
-			}
-			if (bs.write_b) {
-				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE;
-			}
-			if (bs.write_a) {
-				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
-			}
-
-			if (i > 0 && all_attachments_same_blend) {
-				all_attachments_same_blend = &(&pipeline_desc.BlendState)->RenderTarget[i] == &(&pipeline_desc.BlendState)->RenderTarget[0];
-			}
-		}
-
-		// Per D3D12 docs, if logic op used, independent blending is not supported.
-		ERR_FAIL_COND_V(p_blend_state.enable_logic_op && !all_attachments_same_blend, RID());
-
-		(&pipeline_desc.BlendState)->IndependentBlendEnable = !all_attachments_same_blend;
-	}
-
-	dyn_params.blend_constant = p_blend_state.blend_constant;
-
-	// Stages bytecodes + specialization constants.
-
-	pipeline_desc.pRootSignature = shader->root_signature.Get();
-
-#ifdef DEBUG_CREATE_DEBUG_PSO
-	pipeline_desc.Flags = D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;
-#endif
-
-	HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
-	Error err = _apply_specialization_constants(shader, p_specialization_constants, final_stages_bytecode);
-	ERR_FAIL_COND_V(err, RID());
-
-#ifdef DEV_ENABLED
-	// Ensure signing worked.
-	for (KeyValue<ShaderStage, Vector<uint8_t>> &E : final_stages_bytecode) {
-		bool any_non_zero = false;
-		for (int j = 0; j < 16; j++) {
-			if (E.value.ptr()[4 + j]) {
-				any_non_zero = true;
-				break;
-			}
-		}
-		DEV_ASSERT(any_non_zero);
-	}
-#endif
-
-	if (shader->stages_bytecode.has(SHADER_STAGE_VERTEX)) {
-		pipeline_desc.VS = D3D12_SHADER_BYTECODE{
-			final_stages_bytecode[SHADER_STAGE_VERTEX].ptr(),
-			(SIZE_T)final_stages_bytecode[SHADER_STAGE_VERTEX].size()
-		};
-	}
-	if (shader->stages_bytecode.has(SHADER_STAGE_FRAGMENT)) {
-		pipeline_desc.PS = D3D12_SHADER_BYTECODE{
-			final_stages_bytecode[SHADER_STAGE_FRAGMENT].ptr(),
-			(SIZE_T)final_stages_bytecode[SHADER_STAGE_FRAGMENT].size()
-		};
-	}
-
-	RenderPipeline pipeline;
-	{
-		ComPtr<ID3D12Device2> device2;
-		device.As(&device2);
-		HRESULT res = {};
-		if (device2) {
-			D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
-			pssd.pPipelineStateSubobjectStream = &pipeline_desc;
-			pssd.SizeInBytes = sizeof(pipeline_desc);
-			res = device2->CreatePipelineState(&pssd, IID_PPV_ARGS(pipeline.pso.GetAddressOf()));
-		} else {
-			// Some features won't be available (like depth bounds).
-			// TODO: Check and/or report error then?
-			D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = pipeline_desc.GraphicsDescV0();
-			res = device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(pipeline.pso.GetAddressOf()));
-		}
-		ERR_FAIL_COND_V_MSG(res, RID(), "CreateGraphicsPipelineState failed with error " + vformat("0x%08ux", res) + " for shader '" + shader->name + "'.");
-
-#ifdef DEBUG_SAVE_PSO_BLOBS
-		_save_pso_blob(pipeline.pso.Get(), shader, p_specialization_constants);
-#endif
-#ifdef DEBUG_SAVE_DXIL_BLOBS
-		_save_stages_bytecode(final_stages_bytecode, shader, p_shader, p_specialization_constants);
-#endif
-	}
-
-	{
-		Vector<Vector<UniformBindingInfo>> bindings;
-		bindings.resize(shader->sets.size());
-		for (int i = 0; i < shader->sets.size(); i++) {
-			bindings.write[i].resize(shader->sets[i].uniforms.size());
-			for (int j = 0; j < shader->sets[i].uniforms.size(); j++) {
-				bindings.write[i].write[j] = shader->sets[i].uniforms[j].binding;
-			}
-		}
-		pipeline_bindings[next_pipeline_binding_id] = bindings;
-		pipeline.bindings_id = next_pipeline_binding_id;
-		next_pipeline_binding_id++;
-	}
-
-	pipeline.root_signature_crc = shader->root_signature_crc;
-	pipeline.set_formats = shader->set_formats;
-	pipeline.shader = p_shader;
-	pipeline.spirv_push_constant_size = shader->spirv_push_constant_size;
-	pipeline.dxil_push_constant_size = shader->dxil_push_constant_size;
-	pipeline.nir_runtime_data_root_param_idx = shader->nir_runtime_data_root_param_idx;
-	pipeline.dyn_params = dyn_params;
-
-#ifdef DEBUG_ENABLED
-	pipeline.validation.dynamic_state = p_dynamic_state_flags;
-	pipeline.validation.framebuffer_format = p_framebuffer_format;
-	pipeline.validation.render_pass = p_for_render_pass;
-	pipeline.validation.vertex_format = p_vertex_format;
-	pipeline.validation.uses_restart_indices = pipeline_desc.IBStripCutValue != D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
-
-	static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = {
-		1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1
-	};
-	pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive];
-	static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = {
-		1,
-		2,
-		2,
-		2,
-		2,
-		3,
-		3,
-		3,
-		3,
-		3,
-		1,
-	};
-	pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];
-#endif
-	// Create ID to associate with this pipeline.
-	RID id = render_pipeline_owner.make_rid(pipeline);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	// Now add all the dependencies.
-	_add_dependency(id, p_shader);
-	return id;
-}
-
-bool RenderingDeviceD3D12::render_pipeline_is_valid(RID p_pipeline) {
-	_THREAD_SAFE_METHOD_
-	return render_pipeline_owner.owns(p_pipeline);
-}
-
-/**************************/
-/**** COMPUTE PIPELINE ****/
-/**************************/
-
-RID RenderingDeviceD3D12::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-#ifdef DEV_ENABLED
-//#define DEBUG_CREATE_DEBUG_PSO
-//#define DEBUG_SAVE_PSO_BLOBS
-//#define DEBUG_SAVE_DXIL_BLOBS
-#endif
-	_THREAD_SAFE_METHOD_
-
-	// Needs a shader.
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
-			"Non-compute shaders can't be used in compute pipelines");
-
-	CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
-
-	// Stages bytecodes + specialization constants.
-
-	pipeline_desc.pRootSignature = shader->root_signature.Get();
-
-#ifdef DEBUG_CREATE_DEBUG_PSO
-	pipeline_desc.Flags = D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;
-#endif
-
-	HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
-	Error err = _apply_specialization_constants(shader, p_specialization_constants, final_stages_bytecode);
-	ERR_FAIL_COND_V(err, RID());
-
-	pipeline_desc.CS = D3D12_SHADER_BYTECODE{
-		final_stages_bytecode[SHADER_STAGE_COMPUTE].ptr(),
-		(SIZE_T)final_stages_bytecode[SHADER_STAGE_COMPUTE].size()
-	};
-
-	ComputePipeline pipeline;
-	{
-		ComPtr<ID3D12Device2> device2;
-		device.As(&device2);
-		HRESULT res = {};
-		if (device2) {
-			D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
-			pssd.pPipelineStateSubobjectStream = &pipeline_desc;
-			pssd.SizeInBytes = sizeof(pipeline_desc);
-			res = device2->CreatePipelineState(&pssd, IID_PPV_ARGS(pipeline.pso.GetAddressOf()));
-		} else {
-			D3D12_COMPUTE_PIPELINE_STATE_DESC desc = pipeline_desc.ComputeDescV0();
-			res = device->CreateComputePipelineState(&desc, IID_PPV_ARGS(pipeline.pso.GetAddressOf()));
-		}
-		ERR_FAIL_COND_V_MSG(res, RID(), "CreateComputePipelineState failed with error " + vformat("0x%08ux", res) + " for shader '" + shader->name + "'.");
-
-#ifdef DEBUG_SAVE_PSO_BLOBS
-		_save_pso_blob(pipeline.pso.Get(), shader, p_specialization_constants);
-#endif
-#ifdef DEBUG_SAVE_DXIL_BLOBS
-		_save_stages_bytecode(final_stages_bytecode, shader, p_shader, p_specialization_constants);
-#endif
-	}
-
-	{
-		Vector<Vector<UniformBindingInfo>> bindings;
-		bindings.resize(shader->sets.size());
-		for (int i = 0; i < shader->sets.size(); i++) {
-			bindings.write[i].resize(shader->sets[i].uniforms.size());
-			for (int j = 0; j < shader->sets[i].uniforms.size(); j++) {
-				bindings.write[i].write[j] = shader->sets[i].uniforms[j].binding;
-			}
-		}
-		pipeline_bindings[next_pipeline_binding_id] = bindings;
-		pipeline.bindings_id = next_pipeline_binding_id;
-		next_pipeline_binding_id++;
-	}
-
-	pipeline.root_signature_crc = shader->root_signature_crc;
-	pipeline.set_formats = shader->set_formats;
-	pipeline.shader = p_shader;
-	pipeline.spirv_push_constant_size = shader->spirv_push_constant_size;
-	pipeline.dxil_push_constant_size = shader->dxil_push_constant_size;
-	pipeline.local_group_size[0] = shader->compute_local_size[0];
-	pipeline.local_group_size[1] = shader->compute_local_size[1];
-	pipeline.local_group_size[2] = shader->compute_local_size[2];
-
-	// Create ID to associate with this pipeline.
-	RID id = compute_pipeline_owner.make_rid(pipeline);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	// Now add all the dependencies.
-	_add_dependency(id, p_shader);
-	return id;
-}
-
-bool RenderingDeviceD3D12::compute_pipeline_is_valid(RID p_pipeline) {
-	return compute_pipeline_owner.owns(p_pipeline);
-}
-
-/****************/
-/**** SCREEN ****/
-/****************/
-
-int RenderingDeviceD3D12::screen_get_width(DisplayServer::WindowID p_screen) const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen");
-	return context->window_get_width(p_screen);
-}
-
-int RenderingDeviceD3D12::screen_get_height(DisplayServer::WindowID p_screen) const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen");
-
-	return context->window_get_height(p_screen);
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceD3D12::screen_get_framebuffer_format() const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
-
-	// Very hacky, but not used often per frame so I guess ok.
-	DXGI_FORMAT d3d12_format = context->get_screen_format();
-	DataFormat format = DATA_FORMAT_MAX;
-	for (int i = 0; i < DATA_FORMAT_MAX; i++) {
-		if (d3d12_format == d3d12_formats[i].general_format) {
-			format = DataFormat(i);
-			break;
-		}
-	}
-
-	ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID);
-
-	AttachmentFormat attachment;
-	attachment.format = format;
-	attachment.samples = TEXTURE_SAMPLES_1;
-	attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-	Vector<AttachmentFormat> screen_attachment;
-	screen_attachment.push_back(attachment);
-	return const_cast<RenderingDeviceD3D12 *>(this)->framebuffer_format_create(screen_attachment);
-}
-
-/*******************/
-/**** DRAW LIST ****/
-/*******************/
-
-RenderingDevice::DrawListID RenderingDeviceD3D12::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	if (!context->window_is_valid_swapchain(p_screen)) {
-		return INVALID_ID;
-	}
-
-	Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen));
-
-	_draw_list_allocate(Rect2i(Vector2i(), size), 0, 0);
-
-	Vector<Color> clear_colors;
-	clear_colors.push_back(p_clear_color);
-
-	curr_screen_framebuffer = Framebuffer();
-	curr_screen_framebuffer.window_id = p_screen;
-	curr_screen_framebuffer.format_id = screen_get_framebuffer_format();
-	curr_screen_framebuffer.size = size;
-	curr_screen_framebuffer.screen_rtv_handle = context->window_get_framebuffer_rtv_handle(p_screen);
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-	Error err = _draw_list_render_pass_begin(&curr_screen_framebuffer, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_DROP, FINAL_ACTION_DISCARD, clear_colors, 0.0f, 0, Rect2i(), Point2i(), size, command_list, Vector<RID>());
-
-	if (err != OK) {
-		return INVALID_ID;
-	}
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-
-Error RenderingDeviceD3D12::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, Point2i viewport_offset, Point2i viewport_size, ID3D12GraphicsCommandList *command_list, const Vector<RID> &p_storage_textures) {
-	const FramebufferFormat &fb_format = framebuffer_formats[framebuffer->format_id];
-
-	bool is_screen = framebuffer->window_id != DisplayServer::INVALID_WINDOW_ID;
-	if (!is_screen) {
-		ERR_FAIL_COND_V(fb_format.attachments.size() != framebuffer->texture_ids.size(), ERR_BUG);
-	}
-
-	CD3DX12_RECT region_rect(0, 0, framebuffer->size.x, framebuffer->size.y);
-	if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
-		Rect2i viewport(viewport_offset, viewport_size);
-		Rect2i regioni = p_region;
-		if (!viewport.encloses(regioni)) {
-			ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle");
-		}
-		viewport_offset = regioni.position;
-		viewport_size = regioni.size;
-
-		region_rect = CD3DX12_RECT(
-				p_region.position.x,
-				p_region.position.y,
-				p_region.position.x + p_region.size.x,
-				p_region.position.y + p_region.size.y);
-	}
-
-	if (p_initial_color_action == INITIAL_ACTION_CLEAR) { // Check clear values.
-		int color_count = 0;
-		if (is_screen) {
-			color_count = 1;
-
-		} else {
-			for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
-				Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-				if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) {
-					if (!texture || !texture->is_resolve_buffer) {
-						color_count++;
-					}
-				}
-			}
-		}
-		ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_count, ERR_INVALID_PARAMETER,
-				"Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
-	}
-
-	struct SetupInfo {
-		enum {
-			ACTION_NONE,
-			ACTION_DISCARD,
-			ACTION_CLEAR,
-		} action = ACTION_NONE;
-		UINT num_rects = 0;
-		D3D12_RECT *rect_ptr = nullptr;
-		D3D12_RESOURCE_STATES new_state = {};
-
-		SetupInfo(InitialAction p_action, D3D12_RECT *p_region_rect, bool p_is_color) {
-			switch (p_action) {
-				case INITIAL_ACTION_CLEAR: {
-					action = ACTION_CLEAR;
-				} break;
-				case INITIAL_ACTION_CLEAR_REGION: {
-					action = ACTION_CLEAR;
-					num_rects = 1;
-					rect_ptr = p_region_rect;
-				} break;
-				case INITIAL_ACTION_CLEAR_REGION_CONTINUE: {
-					action = ACTION_CLEAR;
-					num_rects = 1;
-					rect_ptr = p_region_rect;
-				} break;
-				case INITIAL_ACTION_KEEP: {
-				} break;
-				case INITIAL_ACTION_DROP: {
-					action = ACTION_DISCARD; // TODO: Are we really intended to do a resource Discard() as initial action, when final action can already do?
-				} break;
-				case INITIAL_ACTION_CONTINUE: {
-				} break;
-			}
-		}
-	};
-
-	SetupInfo setup_color(p_initial_color_action, &region_rect, true);
-	SetupInfo setup_depth(p_initial_depth_action, &region_rect, false);
-
-	draw_list_bound_textures.clear();
-	draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
-	draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
-
-	ID3D12Resource **discards = (ID3D12Resource **)alloca(sizeof(ID3D12Resource *) * fb_format.attachments.size());
-	uint32_t num_discards = 0;
-
-	struct RTVClear {
-		D3D12_CPU_DESCRIPTOR_HANDLE handle;
-		Color color;
-	};
-	RTVClear *rtv_clears = (RTVClear *)alloca(sizeof(RTVClear) * fb_format.attachments.size());
-	uint32_t num_rtv_clears = 0;
-
-	bool dsv_clear = false;
-
-	DescriptorsHeap::Walker rtv_heap_walker = framebuffer->rtv_heap.make_walker();
-
-	int color_index = 0;
-	for (int i = 0; i < fb_format.attachments.size(); i++) {
-		RID texture_rid;
-		Texture *texture = nullptr;
-		if (!is_screen) {
-			texture_rid = framebuffer->texture_ids[i];
-			if (texture_rid.is_null()) {
-				color_index++;
-				continue;
-			}
-
-			texture = texture_owner.get_or_null(texture_rid);
-			ERR_FAIL_NULL_V(texture, ERR_BUG);
-
-			texture->bound = true;
-			draw_list_bound_textures.push_back(texture_rid);
-		}
-
-		// We can setup a framebuffer where we write to our VRS texture to set it up.
-		// We make the assumption here that if our texture is actually used as our VRS attachment,
-		// it is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses (in Vulkan).
-		// [[VRS_EVERY_SUBPASS_OR_NONE]]
-		bool is_vrs = fb_format.attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == fb_format.passes[0].vrs_attachment;
-		if (is_vrs) {
-			DEV_ASSERT(!is_screen);
-
-			DEV_ASSERT(texture->owner_mipmaps == 1);
-			DEV_ASSERT(texture->owner_layers == 1);
-			_resource_transition_batch(texture, 0, texture->planes, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
-		} else {
-			if ((fb_format.attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-				if (!is_screen) { // Screen backbuffers are transitioned in prepare_buffers().
-					for (uint32_t j = 0; j < texture->layers; j++) {
-						for (uint32_t k = 0; k < texture->mipmaps; k++) {
-							uint32_t subresource = D3D12CalcSubresource(texture->base_mipmap + k, texture->base_layer + j, 0, texture->owner_mipmaps, texture->owner_layers);
-							_resource_transition_batch(texture, subresource, texture->planes, D3D12_RESOURCE_STATE_RENDER_TARGET);
-						}
-					}
-				}
-
-				if (setup_color.action == SetupInfo::ACTION_DISCARD) {
-					ID3D12Resource *resource = is_screen ? context->window_get_framebuffer_texture(framebuffer->window_id) : texture->resource;
-					discards[num_discards++] = resource;
-				} else if (setup_color.action == SetupInfo::ACTION_CLEAR) {
-					D3D12_CPU_DESCRIPTOR_HANDLE handle = is_screen ? framebuffer->screen_rtv_handle : rtv_heap_walker.get_curr_cpu_handle();
-					Color clear_color = color_index < p_clear_colors.size() ? p_clear_colors[color_index] : Color();
-					rtv_clears[num_rtv_clears++] = RTVClear{ handle, clear_color };
-				}
-
-				color_index++;
-				if (!is_screen) {
-					rtv_heap_walker.advance();
-				}
-			} else if ((fb_format.attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-				DEV_ASSERT(!is_screen);
-
-				for (uint32_t j = 0; j < texture->layers; j++) {
-					for (uint32_t k = 0; k < texture->mipmaps; k++) {
-						uint32_t subresource = D3D12CalcSubresource(texture->base_mipmap + k, texture->base_layer + j, 0, texture->owner_mipmaps, texture->owner_layers);
-						_resource_transition_batch(texture, subresource, texture->planes, D3D12_RESOURCE_STATE_DEPTH_WRITE);
-					}
-				}
-
-				if (setup_depth.action == SetupInfo::ACTION_DISCARD) {
-					discards[num_discards++] = texture->resource;
-				} else if (setup_depth.action == SetupInfo::ACTION_CLEAR) {
-					dsv_clear = true;
-				}
-			}
-		}
-	}
-
-	for (int i = 0; i < p_storage_textures.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(p_storage_textures[i]);
-		if (!texture) {
-			continue;
-		}
-		ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage.");
-	}
-
-	_resource_transitions_flush(frames[frame].draw_command_list.Get());
-
-	for (uint32_t i = 0; i < num_discards; i++) {
-		command_list->DiscardResource(discards[i], nullptr);
-	}
-	for (uint32_t i = 0; i < num_rtv_clears; i++) {
-		command_list->ClearRenderTargetView(
-				rtv_clears[i].handle,
-				rtv_clears[i].color.components,
-				setup_color.num_rects,
-				setup_color.rect_ptr);
-	}
-
-	if (dsv_clear) {
-		command_list->ClearDepthStencilView(
-				framebuffer->dsv_heap.get_heap()->GetCPUDescriptorHandleForHeapStart(),
-				D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL,
-				p_clear_depth,
-				p_clear_stencil,
-				setup_depth.num_rects,
-				setup_depth.rect_ptr);
-	}
-
-	{
-		CD3DX12_VIEWPORT viewport(
-				viewport_offset.x,
-				viewport_offset.y,
-				viewport_size.x,
-				viewport_size.y,
-				0.0f,
-				1.0f);
-		command_list->RSSetViewports(1, &viewport);
-
-		CD3DX12_RECT scissor(
-				viewport_offset.x,
-				viewport_offset.y,
-				viewport_offset.x + viewport_size.x,
-				viewport_offset.y + viewport_size.y);
-		command_list->RSSetScissorRects(1, &scissor);
-	}
-
-	draw_list_subpass_count = fb_format.passes.size();
-	draw_list_current_subpass = 0;
-	draw_list_final_color_action = p_final_color_action;
-	draw_list_final_depth_action = p_final_depth_action;
-	draw_list_framebuffer = framebuffer;
-	draw_list_viewport_size = viewport_size;
-
-	_draw_list_subpass_begin();
-
-	return OK;
-}
-
-RenderingDevice::DrawListID RenderingDeviceD3D12::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-	Error err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, Point2i(), framebuffer->size, command_list, p_storage_textures);
-
-	if (err != OK) {
-		return INVALID_ID;
-	}
-
-	_draw_list_allocate(Rect2i(Point2i(), framebuffer->size), 0, 0);
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-
-Error RenderingDeviceD3D12::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time.");
-
-	ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION);
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION);
-
-	ID3D12GraphicsCommandList *frame_command_list = frames[frame].draw_command_list.Get();
-	Error err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, Point2i(), framebuffer->size, frame_command_list, p_storage_textures);
-
-	if (err != OK) {
-		return ERR_CANT_CREATE;
-	}
-
-	err = _draw_list_allocate(Rect2i(Point2i(), framebuffer->size), p_splits, 0);
-	if (err != OK) {
-		return err;
-	}
-
-	for (uint32_t i = 0; i < p_splits; i++) {
-		// In Vulkan, we'd be setting viewports and scissors for each split here;
-		// D3D12 doesn't need it (it's even forbidden, for that matter).
-
-		r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
-	}
-
-	return OK;
-}
-
-RenderingDeviceD3D12::DrawList *RenderingDeviceD3D12::_get_draw_list_ptr(DrawListID p_id) {
-	if (p_id < 0) {
-		return nullptr;
-	}
-
-	if (!draw_list) {
-		return nullptr;
-	} else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) {
-		if (draw_list_split) {
-			return nullptr;
-		}
-		return draw_list;
-	} else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) {
-		if (!draw_list_split) {
-			return nullptr;
-		}
-
-		uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
-
-		if (index >= draw_list_count) {
-			return nullptr;
-		}
-
-		return &draw_list[index];
-	} else {
-		return nullptr;
-	}
-}
-
-void RenderingDeviceD3D12::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	dl->command_list->OMSetBlendFactor(p_color.components);
-}
-
-void RenderingDeviceD3D12::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline);
-	ERR_FAIL_NULL(pipeline);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer->format_id && pipeline->validation.render_pass != draw_list_current_subpass);
-#endif
-
-	if (p_render_pipeline == dl->state.pipeline) {
-		return; // Redundant state, return.
-	}
-
-	dl->state.pipeline = p_render_pipeline;
-	dl->state.pso = pipeline->pso.Get();
-
-	dl->command_list->IASetPrimitiveTopology(pipeline->dyn_params.primitive_topology);
-	dl->command_list->OMSetBlendFactor(pipeline->dyn_params.blend_constant.components);
-	dl->command_list->OMSetStencilRef(pipeline->dyn_params.stencil_reference);
-
-	ID3D12GraphicsCommandList1 *command_list_1 = nullptr;
-	dl->command_list->QueryInterface<ID3D12GraphicsCommandList1>(&command_list_1);
-	if (command_list_1) {
-		command_list_1->OMSetDepthBounds(pipeline->dyn_params.depth_bounds_min, pipeline->dyn_params.depth_bounds_max);
-		command_list_1->Release();
-	}
-
-	Shader *shader = shader_owner.get_or_null(pipeline->shader);
-
-	if (dl->state.pipeline_shader != pipeline->shader) {
-		if (dl->state.root_signature_crc != pipeline->root_signature_crc) {
-			dl->command_list->SetGraphicsRootSignature(shader->root_signature.Get());
-			dl->state.root_signature_crc = pipeline->root_signature_crc;
-
-			// Root signature changed, so current descriptor set bindings become invalid.
-			for (uint32_t i = 0; i < dl->state.set_count; i++) {
-				dl->state.sets[i].bound = false;
-			}
-
-			if (pipeline->nir_runtime_data_root_param_idx != UINT32_MAX) {
-				// Set the viewport size part of the DXIL-NIR runtime data, which is the only we know to need currently.
-				constexpr dxil_spirv_vertex_runtime_data dummy_data = {};
-				uint32_t offset = constexpr((char *)&dummy_data.viewport_width - (char *)&dummy_data) / 4;
-				dl->command_list->SetGraphicsRoot32BitConstants(pipeline->nir_runtime_data_root_param_idx, 2, &draw_list_viewport_size, offset);
-			}
-		}
-
-		const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
-		dl->state.set_count = pipeline->set_formats.size(); // Update set count.
-		for (uint32_t i = 0; i < dl->state.set_count; i++) {
-			dl->state.sets[i].pipeline_expected_format = pformats[i];
-#ifdef DEV_ENABLED
-			dl->state.sets[i]._pipeline_expected_format = pformats[i] ? &uniform_set_format_cache_reverse[pformats[i] - 1]->key().uniform_info : nullptr;
-#endif
-		}
-
-		if (pipeline->spirv_push_constant_size) {
-#ifdef DEBUG_ENABLED
-			dl->validation.pipeline_push_constant_supplied = false;
-#endif
-		}
-
-		dl->state.pipeline_shader = pipeline->shader;
-		dl->state.pipeline_dxil_push_constant_size = pipeline->dxil_push_constant_size;
-		dl->state.pipeline_bindings_id = pipeline->bindings_id;
-#ifdef DEV_ENABLED
-		dl->state._shader = shader;
-#endif
-	}
-
-#ifdef DEBUG_ENABLED
-	// Update render pass pipeline info.
-	dl->validation.pipeline_active = true;
-	dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;
-	dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format;
-	dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices;
-	dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor;
-	dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum;
-	dl->validation.pipeline_spirv_push_constant_size = pipeline->spirv_push_constant_size;
-#endif
-}
-
-void RenderingDeviceD3D12::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(uniform_set);
-
-	if (p_index > dl->state.set_count) {
-		dl->state.set_count = p_index;
-	}
-
-	dl->state.sets[p_index].bound = false; // Needs rebind.
-	dl->state.sets[p_index].uniform_set_format = uniform_set->format;
-	dl->state.sets[p_index].uniform_set = p_uniform_set;
-#ifdef DEV_ENABLED
-	dl->state.sets[p_index]._uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-#endif
-
-#ifdef DEBUG_ENABLED
-	{ // Validate that textures bound are not attached as framebuffer bindings.
-		uint32_t attachable_count = uniform_set->attachable_textures.size();
-		const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();
-		uint32_t bound_count = draw_list_bound_textures.size();
-		const RID *bound_ptr = draw_list_bound_textures.ptr();
-		for (uint32_t i = 0; i < attachable_count; i++) {
-			for (uint32_t j = 0; j < bound_count; j++) {
-				ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j],
-						"Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed.");
-			}
-		}
-	}
-#endif
-}
-
-void RenderingDeviceD3D12::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);
-	ERR_FAIL_NULL(vertex_array);
-
-	if (dl->state.vertex_array == p_vertex_array) {
-		return; // Already set.
-	}
-
-	dl->state.vertex_array = p_vertex_array;
-
-#ifdef DEBUG_ENABLED
-	dl->validation.vertex_format = vertex_array->description;
-	dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed;
-#endif
-	dl->validation.vertex_array_size = vertex_array->vertex_count;
-
-	for (Buffer *buffer : vertex_array->unique_buffers) {
-		_resource_transition_batch(buffer, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
-	}
-	_resource_transitions_flush(dl->command_list);
-
-	dl->command_list->IASetVertexBuffers(0, vertex_array->views.size(), vertex_array->views.ptr());
-}
-
-void RenderingDeviceD3D12::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const IndexArray *index_array = index_array_owner.get_or_null(p_index_array);
-	ERR_FAIL_NULL(index_array);
-
-	if (dl->state.index_array == p_index_array) {
-		return; // Already set.
-	}
-
-	dl->state.index_array = p_index_array;
-#ifdef DEBUG_ENABLED
-	dl->validation.index_array_max_index = index_array->max_index;
-#endif
-	dl->validation.index_array_size = index_array->indices;
-	dl->validation.index_array_offset = index_array->offset;
-
-	_resource_transition_batch(index_array->buffer, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);
-	_resource_transitions_flush(dl->command_list);
-
-	dl->command_list->IASetIndexBuffer(&index_array->view);
-}
-
-void RenderingDeviceD3D12::draw_list_set_line_width(DrawListID p_list, float p_width) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	if (!Math::is_equal_approx(p_width, 1.0f)) {
-		ERR_FAIL_MSG("Setting line widths other than 1.0 is not supported by the Direct3D 12 rendering driver.");
-	}
-}
-
-void RenderingDeviceD3D12::_bind_uniform_set(UniformSet *p_uniform_set, const Shader::Set &p_shader_set, const Vector<UniformBindingInfo> &p_bindings, ID3D12GraphicsCommandList *p_command_list, bool p_for_compute) {
-	using SetRootDescriptorTableFn = void (STDMETHODCALLTYPE ID3D12GraphicsCommandList::*)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE);
-	SetRootDescriptorTableFn set_root_desc_table_fn = p_for_compute ? &ID3D12GraphicsCommandList::SetComputeRootDescriptorTable : &ID3D12GraphicsCommandList1::SetGraphicsRootDescriptorTable;
-
-	// If this set's descriptors have already been set for the current execution and a compatible root signature, reuse!
-	uint32_t root_sig_crc = p_for_compute ? compute_list->state.root_signature_crc : draw_list->state.root_signature_crc;
-	UniformSet::RecentBind *last_bind = nullptr;
-	for (int i = 0; i < ARRAY_SIZE(p_uniform_set->recent_binds); i++) {
-		if (p_uniform_set->recent_binds[i].execution_index == frames[frame].execution_index) {
-			if (p_uniform_set->recent_binds[i].root_signature_crc == root_sig_crc) {
-				for (const RootDescriptorTable &table : p_uniform_set->recent_binds[i].root_tables.resources) {
-					(p_command_list->*set_root_desc_table_fn)(table.root_param_idx, table.start_gpu_handle);
-				}
-				for (const RootDescriptorTable &table : p_uniform_set->recent_binds[i].root_tables.samplers) {
-					(p_command_list->*set_root_desc_table_fn)(table.root_param_idx, table.start_gpu_handle);
-				}
-#ifdef DEV_ENABLED
-				p_uniform_set->recent_binds[i].uses++;
-				frames[frame].uniform_set_reused++;
-#endif
-				return;
-			} else {
-				if (!last_bind || p_uniform_set->recent_binds[i].uses < last_bind->uses) {
-					// Prefer this one since it's been used less or we still haven't a better option.
-					last_bind = &p_uniform_set->recent_binds[i];
-				}
-			}
-		} else {
-			// Prefer this one since it's unused.
-			last_bind = &p_uniform_set->recent_binds[i];
-			last_bind->uses = 0;
-		}
-	}
-
-	struct {
-		DescriptorsHeap::Walker *resources = nullptr;
-		DescriptorsHeap::Walker *samplers = nullptr;
-	} frame_heap_walkers;
-	frame_heap_walkers.resources = &frames[frame].desc_heap_walkers.resources;
-	frame_heap_walkers.samplers = &frames[frame].desc_heap_walkers.samplers;
-
-	struct {
-		DescriptorsHeap::Walker resources;
-		DescriptorsHeap::Walker samplers;
-	} set_heap_walkers;
-	set_heap_walkers.resources = p_uniform_set->desc_heaps.resources.make_walker();
-	set_heap_walkers.samplers = p_uniform_set->desc_heaps.samplers.make_walker();
-
-#ifdef DEV_ENABLED
-	// Whether we have stages where the uniform is actually used should match
-	// whether we have any root signature locations for it.
-	for (int i = 0; i < p_shader_set.uniforms.size(); i++) {
-		bool has_rs_locations = false;
-		if (p_bindings[i].root_sig_locations.resource.root_param_idx != UINT32_MAX ||
-				p_bindings[i].root_sig_locations.sampler.root_param_idx != UINT32_MAX) {
-			has_rs_locations = true;
-			break;
-		}
-
-		bool has_stages = p_bindings[i].stages;
-
-		DEV_ASSERT(has_rs_locations == has_stages);
-	}
-#endif
-
-	last_bind->root_tables.resources.reserve(p_shader_set.num_root_params.resources);
-	last_bind->root_tables.resources.clear();
-	last_bind->root_tables.samplers.reserve(p_shader_set.num_root_params.samplers);
-	last_bind->root_tables.samplers.clear();
-	last_bind->uses++;
-
-	struct {
-		RootDescriptorTable *resources = nullptr;
-		RootDescriptorTable *samplers = nullptr;
-	} tables;
-	for (int i = 0; i < p_shader_set.uniforms.size(); i++) {
-		const Shader::ShaderUniformInfo &uniform_info = p_shader_set.uniforms[i];
-
-		uint32_t num_resource_descs = 0;
-		uint32_t num_sampler_descs = 0;
-		bool srv_uav_ambiguity = false;
-		_add_descriptor_count_for_uniform(uniform_info.info.type, uniform_info.info.length, false, num_resource_descs, num_sampler_descs, srv_uav_ambiguity);
-
-		bool resource_used = false;
-		if (p_bindings[i].stages) {
-			{
-				const UniformBindingInfo::RootSignatureLocation &rs_loc_resource = p_bindings[i].root_sig_locations.resource;
-				if (rs_loc_resource.root_param_idx != UINT32_MAX) { // Location used?
-					DEV_ASSERT(num_resource_descs);
-					DEV_ASSERT(!(srv_uav_ambiguity && (p_bindings[i].res_class != RES_CLASS_SRV && p_bindings[i].res_class != RES_CLASS_UAV))); // [[SRV_UAV_AMBIGUITY]]
-
-					bool must_flush_table = tables.resources && rs_loc_resource.root_param_idx != tables.resources->root_param_idx;
-					if (must_flush_table) {
-						// Check the root signature data has been filled ordered.
-						DEV_ASSERT(rs_loc_resource.root_param_idx > tables.resources->root_param_idx);
-
-						(p_command_list->*set_root_desc_table_fn)(tables.resources->root_param_idx, tables.resources->start_gpu_handle);
-						tables.resources = nullptr;
-					}
-
-					if (unlikely(frame_heap_walkers.resources->get_free_handles() < num_resource_descs)) {
-						if (!frames[frame].desc_heaps_exhausted_reported.resources) {
-							frames[frame].desc_heaps_exhausted_reported.resources = true;
-							ERR_FAIL_MSG("Cannot bind uniform set because there's no enough room in current frame's RESOURCES descriptor heap.\n"
-										 "Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
-						} else {
-							return;
-						}
-					}
-
-					if (!tables.resources) {
-						DEV_ASSERT(last_bind->root_tables.resources.size() < last_bind->root_tables.resources.get_capacity());
-						last_bind->root_tables.resources.resize(last_bind->root_tables.resources.size() + 1);
-						tables.resources = &last_bind->root_tables.resources[last_bind->root_tables.resources.size() - 1];
-						tables.resources->root_param_idx = rs_loc_resource.root_param_idx;
-						tables.resources->start_gpu_handle = frame_heap_walkers.resources->get_curr_gpu_handle();
-					}
-
-					// If there is ambiguity and it didn't clarify as SRVs, skip them, which come first. [[SRV_UAV_AMBIGUITY]]
-					if (srv_uav_ambiguity && p_bindings[i].res_class != RES_CLASS_SRV) {
-						set_heap_walkers.resources.advance(num_resource_descs);
-					}
-
-					// TODO: Batch to avoid multiple calls where possible (in any case, flush before setting root descriptor tables, or even batch that as well).
-					device->CopyDescriptorsSimple(
-							num_resource_descs,
-							frame_heap_walkers.resources->get_curr_cpu_handle(),
-							set_heap_walkers.resources.get_curr_cpu_handle(),
-							D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
-					frame_heap_walkers.resources->advance(num_resource_descs);
-
-					// If there is ambiguity and it didn't clarify as UAVs, skip them, which come later. [[SRV_UAV_AMBIGUITY]]
-					if (srv_uav_ambiguity && p_bindings[i].res_class != RES_CLASS_UAV) {
-						set_heap_walkers.resources.advance(num_resource_descs);
-					}
-
-					resource_used = true;
-				}
-			}
-
-			{
-				const UniformBindingInfo::RootSignatureLocation &rs_loc_sampler = p_bindings[i].root_sig_locations.sampler;
-				if (rs_loc_sampler.root_param_idx != UINT32_MAX) { // Location used?
-					DEV_ASSERT(num_sampler_descs);
-					DEV_ASSERT(!srv_uav_ambiguity); // [[SRV_UAV_AMBIGUITY]]
-
-					bool must_flush_table = tables.samplers && rs_loc_sampler.root_param_idx != tables.samplers->root_param_idx;
-					if (must_flush_table) {
-						// Check the root signature data has been filled ordered.
-						DEV_ASSERT(rs_loc_sampler.root_param_idx > tables.samplers->root_param_idx);
-
-						(p_command_list->*set_root_desc_table_fn)(tables.samplers->root_param_idx, tables.samplers->start_gpu_handle);
-						tables.samplers = nullptr;
-					}
-
-					if (unlikely(frame_heap_walkers.samplers->get_free_handles() < num_sampler_descs)) {
-						if (!frames[frame].desc_heaps_exhausted_reported.samplers) {
-							frames[frame].desc_heaps_exhausted_reported.samplers = true;
-							ERR_FAIL_MSG("Cannot bind uniform set because there's no enough room in current frame's SAMPLERS descriptors heap.\n"
-										 "Please increase the value of the rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame project setting.");
-						} else {
-							return;
-						}
-					}
-
-					if (!tables.samplers) {
-						DEV_ASSERT(last_bind->root_tables.samplers.size() < last_bind->root_tables.samplers.get_capacity());
-						last_bind->root_tables.samplers.resize(last_bind->root_tables.samplers.size() + 1);
-						tables.samplers = &last_bind->root_tables.samplers[last_bind->root_tables.samplers.size() - 1];
-						tables.samplers->root_param_idx = rs_loc_sampler.root_param_idx;
-						tables.samplers->start_gpu_handle = frame_heap_walkers.samplers->get_curr_gpu_handle();
-					}
-
-					// TODO: Batch to avoid multiple calls where possible (in any case, flush before setting root descriptor tables, or even batch that as well).
-					device->CopyDescriptorsSimple(
-							num_sampler_descs,
-							frame_heap_walkers.samplers->get_curr_cpu_handle(),
-							set_heap_walkers.samplers.get_curr_cpu_handle(),
-							D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
-					frame_heap_walkers.samplers->advance(num_sampler_descs);
-				}
-			}
-		}
-
-		// Uniform set descriptor heaps are always full (descriptors are created for every uniform in them) despite
-		// the shader variant a given set is created upon may not need all of them due to DXC optimizations.
-		// Therefore, at this point we have to advance through the descriptor set descriptor's heap unconditionally.
-
-		set_heap_walkers.resources.advance(num_resource_descs);
-		if (srv_uav_ambiguity) {
-			DEV_ASSERT(num_resource_descs);
-			if (!resource_used) {
-				set_heap_walkers.resources.advance(num_resource_descs); // Additional skip, since both SRVs and UAVs have to be bypassed.
-			}
-		}
-
-		set_heap_walkers.samplers.advance(num_sampler_descs);
-	}
-
-	DEV_ASSERT(set_heap_walkers.resources.is_at_eof());
-	DEV_ASSERT(set_heap_walkers.samplers.is_at_eof());
-
-	{
-		bool must_flush_table = tables.resources;
-		if (must_flush_table) {
-			(p_command_list->*set_root_desc_table_fn)(tables.resources->root_param_idx, tables.resources->start_gpu_handle);
-		}
-	}
-	{
-		bool must_flush_table = tables.samplers;
-		if (must_flush_table) {
-			(p_command_list->*set_root_desc_table_fn)(tables.samplers->root_param_idx, tables.samplers->start_gpu_handle);
-		}
-	}
-
-	last_bind->root_signature_crc = root_sig_crc;
-	last_bind->execution_index = frames[frame].execution_index;
-}
-
-void RenderingDeviceD3D12::_apply_uniform_set_resource_states(const UniformSet *p_uniform_set, const Shader::Set &p_shader_set) {
-	for (const UniformSet::StateRequirement &sr : p_uniform_set->resource_states) {
-#ifdef DEV_ENABLED
-		{
-			uint32_t stages = 0;
-			D3D12_RESOURCE_STATES wanted_state = {};
-			bool writable = false;
-			// Doing the full loop for debugging since the real one below may break early,
-			// but we want an exhaustive check
-			uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
-			for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
-				uint64_t bit_mask = ((uint64_t)1 << bit);
-				if (likely((inv_uniforms_mask & bit_mask))) {
-					continue;
-				}
-				inv_uniforms_mask |= bit_mask;
-
-				const Shader::ShaderUniformInfo &info = p_shader_set.uniforms[bit];
-				if (unlikely(!info.binding.stages)) {
-					continue;
-				}
-
-				D3D12_RESOURCE_STATES required_states = sr.states;
-
-				// Resolve a case of SRV/UAV ambiguity now. [[SRV_UAV_AMBIGUITY]]
-				if ((required_states & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE) && (required_states & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
-					if (info.binding.res_class == RES_CLASS_SRV) {
-						required_states &= ~D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					} else {
-						required_states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					}
-				}
-
-				if (stages) { // Second occurrence at least?
-					CRASH_COND_MSG(info.info.writable != writable, "A resource is used in the same uniform set both as R/O and R/W. That's not supported and shouldn't happen.");
-					CRASH_COND_MSG(required_states != wanted_state, "A resource is used in the same uniform set with different resource states. The code needs to be enhanced to support that.");
-				} else {
-					wanted_state = required_states;
-					stages |= info.binding.stages;
-					writable = info.info.writable;
-				}
-
-				DEV_ASSERT((wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == (bool)(wanted_state & D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
-
-				if (wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS || wanted_state == D3D12_RESOURCE_STATE_RENDER_TARGET) {
-					if (!sr.is_buffer) {
-						Texture *texture = (Texture *)sr.resource;
-						CRASH_COND_MSG(texture->resource != texture->owner_resource, "The texture format used for UAV or RTV must be the main one.");
-					}
-				}
-			}
-		}
-#endif
-
-		// We may have assumed D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE for a resource,
-		// because at uniform set creation time we couldn't know for sure which stages
-		// it would be used in (due to the fact that a set can be created against a different,
-		// albeit compatible, shader, which may make a different usage in the end).
-		// However, now we know and can exclude up to one unneeded state.
-
-		// TODO: If subresources involved already in the needed state, or scheduled for it,
-		// maybe it's more optimal not to do anything here
-
-		uint32_t stages = 0;
-		D3D12_RESOURCE_STATES wanted_state = {};
-		uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
-		for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
-			uint64_t bit_mask = ((uint64_t)1 << bit);
-			if (likely((inv_uniforms_mask & bit_mask))) {
-				continue;
-			}
-			inv_uniforms_mask |= bit_mask;
-
-			const Shader::ShaderUniformInfo &info = p_shader_set.uniforms[bit];
-			if (unlikely(!info.binding.stages)) {
-				continue;
-			}
-
-			if (!stages) {
-				D3D12_RESOURCE_STATES required_states = sr.states;
-
-				// Resolve a case of SRV/UAV ambiguity now. [[SRV_UAV_AMBIGUITY]]
-				if ((required_states & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE) && (required_states & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
-					if (info.binding.res_class == RES_CLASS_SRV) {
-						required_states &= ~D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					} else {
-						required_states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
-					}
-				}
-
-				wanted_state = required_states;
-
-				if (!(wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
-					// By now, we already know the resource is used, and with no PS/NON_PS disjuntive; no need to check further.
-					break;
-				}
-			}
-
-			stages |= info.binding.stages;
-
-			if (stages == (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT) || stages == SHADER_STAGE_COMPUTE_BIT) {
-				// By now, we already know the resource is used, and as both PS/NON_PS; no need to check further.
-				break;
-			}
-		}
-
-		if (likely(wanted_state)) {
-			if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
-				if (stages == SHADER_STAGE_VERTEX_BIT || stages == SHADER_STAGE_COMPUTE_BIT) {
-					D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
-					wanted_state &= ~unneeded_states;
-				} else if (stages == SHADER_STAGE_FRAGMENT_BIT) {
-					D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
-					wanted_state &= ~unneeded_states;
-				}
-			}
-
-			if (likely(wanted_state)) {
-				if (sr.is_buffer) {
-					_resource_transition_batch(sr.resource, 0, 1, wanted_state);
-				} else {
-					Texture *texture = (Texture *)sr.resource;
-					for (uint32_t i = 0; i < texture->layers; i++) {
-						for (uint32_t j = 0; j < texture->mipmaps; j++) {
-							uint32_t subresource = D3D12CalcSubresource(texture->base_mipmap + j, texture->base_layer + i, 0, texture->owner_mipmaps, texture->owner_layers);
-							_resource_transition_batch(texture, subresource, texture->planes, wanted_state, texture->owner_resource);
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
-void RenderingDeviceD3D12::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_spirv_push_constant_size,
-			"This render pipeline requires (" + itos(dl->validation.pipeline_spirv_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
-#endif
-	if (dl->state.pipeline_dxil_push_constant_size) {
-		dl->command_list->SetGraphicsRoot32BitConstants(0, p_data_size / sizeof(uint32_t), p_data, 0);
-	}
-#ifdef DEBUG_ENABLED
-	dl->validation.pipeline_push_constant_supplied = true;
-#endif
-}
-
-void RenderingDeviceD3D12::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
-			"No render pipeline was set before attempting to draw.");
-	if (dl->validation.pipeline_vertex_format != INVALID_ID) {
-		// Pipeline uses vertices, validate format.
-		ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
-				"No vertex array was bound, and render pipeline expects vertices.");
-		// Make sure format is right.
-		ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format,
-				"The vertex format used to create the pipeline does not match the vertex format bound.");
-		// Make sure number of instances is valid.
-		ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed,
-				"Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ").");
-	}
-
-	if (dl->validation.pipeline_spirv_push_constant_size) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-#endif
-
-	// Bind descriptor sets.
-
-	Shader *shader = shader_owner.get_or_null(dl->state.pipeline_shader);
-	struct SetToBind {
-		uint32_t set;
-		UniformSet *uniform_set;
-		const Shader::Set *shader_set;
-	};
-	SetToBind *sets_to_bind = (SetToBind *)alloca(sizeof(SetToBind) * dl->state.set_count);
-	uint32_t num_sets_to_bind = 0;
-	for (uint32_t i = 0; i < dl->state.set_count; i++) {
-		if (dl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
-			if (dl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
-			}
-		}
-#endif
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
-		const Shader::Set &shader_set = shader->sets[i];
-		_apply_uniform_set_resource_states(uniform_set, shader_set);
-		if (!dl->state.sets[i].bound) {
-			sets_to_bind[num_sets_to_bind].set = i;
-			sets_to_bind[num_sets_to_bind].uniform_set = uniform_set;
-			sets_to_bind[num_sets_to_bind].shader_set = &shader_set;
-			num_sets_to_bind++;
-			dl->state.sets[i].bound = true;
-		}
-	}
-
-	_resource_transitions_flush(dl->command_list);
-
-	for (uint32_t i = 0; i < num_sets_to_bind; i++) {
-		_bind_uniform_set(sets_to_bind[i].uniform_set, *sets_to_bind[i].shader_set, pipeline_bindings[dl->state.pipeline_bindings_id][sets_to_bind[i].set], dl->command_list, false);
-	}
-
-	if (dl->state.bound_pso != dl->state.pso) {
-		dl->command_list->SetPipelineState(dl->state.pso);
-		dl->state.bound_pso = dl->state.pso;
-	}
-	if (p_use_indices) {
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(p_procedural_vertices > 0,
-				"Procedural vertices can't be used together with indices.");
-
-		ERR_FAIL_COND_MSG(!dl->validation.index_array_size,
-				"Draw command requested indices, but no index buffer was set.");
-
-		ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
-				"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
-#endif
-		uint32_t to_draw = dl->validation.index_array_size;
-
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
-				"Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ").");
-
-		ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
-				"Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
-#endif
-
-		dl->command_list->DrawIndexedInstanced(to_draw, p_instances, dl->validation.index_array_offset, 0, 0);
-	} else {
-		uint32_t to_draw;
-
-		if (p_procedural_vertices > 0) {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != INVALID_ID,
-					"Procedural vertices requested, but pipeline expects a vertex array.");
-#endif
-			to_draw = p_procedural_vertices;
-		} else {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID,
-					"Draw command lacks indices, but pipeline format does not use vertices.");
-#endif
-			to_draw = dl->validation.vertex_array_size;
-		}
-
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
-				"Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ").");
-
-		ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
-				"Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
-#endif
-
-		dl->command_list->DrawInstanced(to_draw, p_instances, 0, 0);
-	}
-}
-
-void RenderingDeviceD3D12::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-	Rect2i rect = p_rect;
-	rect.position += dl->viewport.position;
-
-	rect = dl->viewport.intersection(rect);
-
-	if (rect.get_area() == 0) {
-		return;
-	}
-	CD3DX12_RECT scissor(
-			rect.position.x,
-			rect.position.y,
-			rect.position.x + rect.size.width,
-			rect.position.y + rect.size.height);
-
-	dl->command_list->RSSetScissorRects(1, &scissor);
-}
-
-void RenderingDeviceD3D12::draw_list_disable_scissor(DrawListID p_list) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	CD3DX12_RECT scissor(
-			dl->viewport.position.x,
-			dl->viewport.position.y,
-			dl->viewport.position.x + dl->viewport.size.width,
-			dl->viewport.position.y + dl->viewport.size.height);
-	dl->command_list->RSSetScissorRects(1, &scissor);
-}
-
-uint32_t RenderingDeviceD3D12::draw_list_get_current_pass() {
-	return draw_list_current_subpass;
-}
-
-void RenderingDeviceD3D12::_draw_list_subpass_begin() { // [[MANUAL_SUBPASSES]]
-	const FramebufferFormat &fb_format = framebuffer_formats[draw_list_framebuffer->format_id];
-	const FramebufferPass &pass = fb_format.passes[draw_list_current_subpass];
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	bool is_screen = draw_list_framebuffer->window_id != DisplayServer::INVALID_WINDOW_ID;
-
-	if (is_screen) {
-		DEV_ASSERT(!draw_list_framebuffer->dsv_heap.get_descriptor_count());
-		command_list->OMSetRenderTargets(1, &draw_list_framebuffer->screen_rtv_handle, true, nullptr);
-	} else {
-		D3D12_CPU_DESCRIPTOR_HANDLE *rtv_handles = (D3D12_CPU_DESCRIPTOR_HANDLE *)alloca(sizeof(D3D12_CPU_DESCRIPTOR_HANDLE) * pass.color_attachments.size());
-		DescriptorsHeap::Walker rtv_heap_walker = draw_list_framebuffer->rtv_heap.make_walker();
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			uint32_t attachment = pass.color_attachments[i];
-			if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-				if (!frames[frame].null_rtv_handle.ptr) {
-					// No null descriptor-handle created for this frame yet.
-
-					if (frames[frame].desc_heap_walkers.rtv.is_at_eof()) {
-						if (!frames[frame].desc_heaps_exhausted_reported.rtv) {
-							frames[frame].desc_heaps_exhausted_reported.rtv = true;
-							ERR_FAIL_MSG("Cannot begin subpass because there's no enough room in current frame's RENDER TARGET descriptors heap.\n"
-										 "Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
-						} else {
-							return;
-						}
-					}
-
-					D3D12_RENDER_TARGET_VIEW_DESC rtv_desc_null = {};
-					rtv_desc_null.Format = DXGI_FORMAT_R8_UINT;
-					rtv_desc_null.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
-					frames[frame].null_rtv_handle = frames[frame].desc_heap_walkers.rtv.get_curr_cpu_handle();
-					device->CreateRenderTargetView(nullptr, &rtv_desc_null, frames[frame].null_rtv_handle);
-					frames[frame].desc_heap_walkers.rtv.advance();
-				}
-				rtv_handles[i] = frames[frame].null_rtv_handle;
-			} else {
-				uint32_t rt_index = draw_list_framebuffer->attachments_handle_inds[attachment];
-				rtv_heap_walker.rewind();
-				rtv_heap_walker.advance(rt_index);
-				rtv_handles[i] = rtv_heap_walker.get_curr_cpu_handle();
-			}
-		}
-
-		D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = {};
-		{
-			DescriptorsHeap::Walker dsv_heap_walker = draw_list_framebuffer->dsv_heap.make_walker();
-			if (pass.depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-				uint32_t ds_index = draw_list_framebuffer->attachments_handle_inds[pass.depth_attachment];
-				dsv_heap_walker.rewind();
-				dsv_heap_walker.advance(ds_index);
-				dsv_handle = dsv_heap_walker.get_curr_cpu_handle();
-			}
-		}
-
-		command_list->OMSetRenderTargets(pass.color_attachments.size(), rtv_handles, false, dsv_handle.ptr ? &dsv_handle : nullptr);
-
-		// [[VRS_EVERY_SUBPASS_OR_NONE]]
-		if (context->get_vrs_capabilities().ss_image_supported && draw_list_current_subpass == 0) {
-			if (execution_index != vrs_state_execution_index) {
-				vrs_state = {};
-			}
-
-			Texture *vrs_texture = nullptr;
-			RID vrs_texture_id;
-			if (pass.vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-				vrs_texture_id = draw_list_framebuffer->texture_ids[pass.vrs_attachment];
-				vrs_texture = texture_owner.get_or_null(vrs_texture_id);
-				if (!vrs_texture) {
-					vrs_texture_id = RID();
-				}
-			}
-
-			if (vrs_texture_id != vrs_state.texture_bound) {
-				ID3D12GraphicsCommandList5 *command_list_5 = nullptr;
-				command_list->QueryInterface<ID3D12GraphicsCommandList5>(&command_list_5);
-				DEV_ASSERT(command_list_5);
-
-				if (vrs_texture_id.is_valid()) {
-					if (!vrs_state.configured) {
-						static const D3D12_SHADING_RATE_COMBINER combiners[D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT] = {
-							D3D12_SHADING_RATE_COMBINER_PASSTHROUGH,
-							D3D12_SHADING_RATE_COMBINER_OVERRIDE,
-						};
-						command_list_5->RSSetShadingRate(D3D12_SHADING_RATE_1X1, combiners);
-						vrs_state.configured = true;
-
-						command_list_5->RSSetShadingRateImage(vrs_texture->resource);
-						vrs_state.texture_bound = vrs_texture_id;
-					}
-				} else {
-					command_list_5->RSSetShadingRateImage(nullptr);
-					vrs_state.texture_bound = RID();
-				}
-
-				command_list_5->Release();
-			}
-
-			vrs_state_execution_index = execution_index;
-		}
-	}
-}
-
-void RenderingDeviceD3D12::_draw_list_subpass_end() { // [[MANUAL_SUBPASSES]]
-	const FramebufferFormat &fb_format = framebuffer_formats[draw_list_framebuffer->format_id];
-	const FramebufferPass &pass = fb_format.passes[draw_list_current_subpass];
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	struct Resolve {
-		ID3D12Resource *src_res;
-		uint32_t src_subres;
-		ID3D12Resource *dst_res;
-		uint32_t dst_subres;
-		DXGI_FORMAT format;
-	};
-	Resolve *resolves = (Resolve *)alloca(sizeof(Resolve) * pass.resolve_attachments.size());
-	uint32_t num_resolves = 0;
-
-	for (int i = 0; i < pass.resolve_attachments.size(); i++) {
-		int32_t color_index = pass.color_attachments[i];
-		int32_t resolve_index = pass.resolve_attachments[i];
-		DEV_ASSERT((color_index == FramebufferPass::ATTACHMENT_UNUSED) == (resolve_index == FramebufferPass::ATTACHMENT_UNUSED));
-		if (color_index == FramebufferPass::ATTACHMENT_UNUSED || draw_list_framebuffer->texture_ids[color_index].is_null()) {
-			continue;
-		}
-
-		Texture *src_tex = texture_owner.get_or_null(draw_list_framebuffer->texture_ids[color_index]);
-		uint32_t src_subresource = D3D12CalcSubresource(src_tex->base_mipmap, src_tex->base_layer, 0, src_tex->owner_mipmaps, src_tex->owner_layers);
-		_resource_transition_batch(src_tex, src_subresource, src_tex->planes, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
-
-		Texture *dst_tex = texture_owner.get_or_null(draw_list_framebuffer->texture_ids[resolve_index]);
-		uint32_t dst_subresource = D3D12CalcSubresource(dst_tex->base_mipmap, dst_tex->base_layer, 0, dst_tex->owner_mipmaps, dst_tex->owner_layers);
-		_resource_transition_batch(dst_tex, dst_subresource, dst_tex->planes, D3D12_RESOURCE_STATE_RESOLVE_DEST);
-
-		resolves[num_resolves].src_res = src_tex->resource;
-		resolves[num_resolves].src_subres = src_subresource;
-		resolves[num_resolves].dst_res = dst_tex->resource;
-		resolves[num_resolves].dst_subres = dst_subresource;
-		resolves[num_resolves].format = d3d12_formats[src_tex->format].general_format;
-		num_resolves++;
-	}
-
-	_resource_transitions_flush(command_list);
-
-	for (uint32_t i = 0; i < num_resolves; i++) {
-		command_list->ResolveSubresource(resolves[i].dst_res, resolves[i].dst_subres, resolves[i].src_res, resolves[i].src_subres, resolves[i].format);
-	}
-}
-
-RenderingDevice::DrawListID RenderingDeviceD3D12::draw_list_switch_to_next_pass() {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V(draw_list == nullptr, INVALID_ID);
-	ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);
-
-	_draw_list_subpass_end();
-	draw_list_current_subpass++;
-	_draw_list_subpass_begin();
-
-	Rect2i viewport;
-	_draw_list_free(&viewport);
-
-	_draw_list_allocate(viewport, 0, draw_list_current_subpass);
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-
-Error RenderingDeviceD3D12::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V(draw_list == nullptr, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER);
-
-	_draw_list_subpass_end();
-	draw_list_current_subpass++;
-	_draw_list_subpass_begin();
-
-	Rect2i viewport;
-	_draw_list_free(&viewport);
-
-	_draw_list_allocate(viewport, p_splits, draw_list_current_subpass);
-
-	for (uint32_t i = 0; i < p_splits; i++) {
-		r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
-	}
-
-	return OK;
-}
-
-Error RenderingDeviceD3D12::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) {
-	if (p_splits == 0) {
-		draw_list = memnew(DrawList);
-		draw_list->command_list = frames[frame].draw_command_list.Get();
-		draw_list->viewport = p_viewport;
-		draw_list_count = 0;
-		draw_list_split = false;
-	} else {
-		if (p_splits > (uint32_t)split_draw_list_allocators.size()) {
-			uint32_t from = split_draw_list_allocators.size();
-			split_draw_list_allocators.resize(p_splits);
-			for (uint32_t i = from; i < p_splits; i++) {
-				HRESULT res = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&split_draw_list_allocators.write[i].command_allocator));
-				ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "CreateCommandAllocator failed with error " + vformat("0x%08ux", res) + ".");
-
-				for (int j = 0; j < frame_count; j++) {
-					ID3D12GraphicsCommandList *command_list = nullptr;
-
-					res = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, split_draw_list_allocators[i].command_allocator, nullptr, IID_PPV_ARGS(&command_list));
-					ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "CreateCommandList failed with error " + vformat("0x%08ux", res) + ".");
-
-					split_draw_list_allocators.write[i].command_lists.push_back(command_list);
-				}
-			}
-		}
-		draw_list = memnew_arr(DrawList, p_splits);
-		draw_list_count = p_splits;
-		draw_list_split = true;
-
-		for (uint32_t i = 0; i < p_splits; i++) {
-			ID3D12GraphicsCommandList *command_list = split_draw_list_allocators[i].command_lists[frame];
-
-			HRESULT res = frames[frame].setup_command_allocator->Reset();
-			ERR_FAIL_COND_V_MSG(ERR_CANT_CREATE, ERR_CANT_CREATE, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-			res = command_list->Reset(split_draw_list_allocators[i].command_allocator, nullptr);
-			if (res) {
-				memdelete_arr(draw_list);
-				draw_list = nullptr;
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-			}
-
-			draw_list[i].command_list = command_list;
-			draw_list[i].viewport = p_viewport;
-		}
-	}
-
-	return OK;
-}
-
-void RenderingDeviceD3D12::_draw_list_free(Rect2i *r_last_viewport) {
-	if (draw_list_split) {
-		// Send all command buffers.
-		for (uint32_t i = 0; i < draw_list_count; i++) {
-			draw_list[i].command_list->Close();
-			frames[frame].draw_command_list->ExecuteBundle(draw_list[i].command_list);
-			if (r_last_viewport) {
-				if (i == 0 || draw_list[i].viewport_set) {
-					*r_last_viewport = draw_list[i].viewport;
-				}
-			}
-		}
-
-		memdelete_arr(draw_list);
-		draw_list = nullptr;
-
-	} else {
-		if (r_last_viewport) {
-			*r_last_viewport = draw_list->viewport;
-		}
-		// Just end the list.
-		memdelete(draw_list);
-		draw_list = nullptr;
-	}
-
-	draw_list_count = 0;
-}
-
-void RenderingDeviceD3D12::draw_list_end(BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive.");
-
-	_draw_list_subpass_end();
-
-	const FramebufferFormat &fb_format = framebuffer_formats[draw_list_framebuffer->format_id];
-	bool is_screen = draw_list_framebuffer->window_id != DisplayServer::INVALID_WINDOW_ID;
-
-	ID3D12GraphicsCommandList *command_list = frames[frame].draw_command_list.Get();
-
-	for (int i = 0; i < fb_format.attachments.size(); i++) {
-		Texture *texture = nullptr;
-		if (!is_screen) {
-			texture = texture_owner.get_or_null(draw_list_framebuffer->texture_ids[i]);
-		}
-		if ((fb_format.attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-			switch (draw_list_final_color_action) {
-				case FINAL_ACTION_READ: {
-					// Nothing to do now.
-				} break;
-				case FINAL_ACTION_DISCARD: {
-					ID3D12Resource *resource = is_screen ? context->window_get_framebuffer_texture(draw_list_framebuffer->window_id) : texture->resource;
-					command_list->DiscardResource(resource, nullptr);
-				} break;
-				case FINAL_ACTION_CONTINUE: {
-					ERR_FAIL_COND(draw_list_unbind_color_textures); // Bug!
-				} break;
-			}
-		} else if ((fb_format.attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-			ERR_FAIL_COND(is_screen); // Bug!
-			switch (draw_list_final_depth_action) {
-				case FINAL_ACTION_READ: {
-					// Nothing to do now.
-				} break;
-				case FINAL_ACTION_DISCARD: {
-					ID3D12Resource *resource = is_screen ? context->window_get_framebuffer_texture(draw_list_framebuffer->window_id) : texture->resource;
-					command_list->DiscardResource(resource, nullptr);
-				} break;
-				case FINAL_ACTION_CONTINUE: {
-					ERR_FAIL_COND(draw_list_unbind_depth_textures); // Bug!
-				} break;
-			}
-		}
-	}
-
-	draw_list_subpass_count = 0;
-	draw_list_current_subpass = 0;
-	draw_list_framebuffer = nullptr;
-
-	_draw_list_free();
-
-	for (int i = 0; i < draw_list_bound_textures.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);
-		ERR_CONTINUE(!texture); // Wtf.
-		if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-			texture->bound = false;
-		}
-		if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-			texture->bound = false;
-		}
-	}
-	draw_list_bound_textures.clear();
-}
-
-/***********************/
-/**** COMPUTE LISTS ****/
-/***********************/
-
-RenderingDevice::ComputeListID RenderingDeviceD3D12::compute_list_begin(bool p_allow_draw_overlap) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	compute_list = memnew(ComputeList);
-	compute_list->command_list = frames[frame].draw_command_list.Get();
-	compute_list->state.allow_draw_overlap = p_allow_draw_overlap;
-
-	return ID_TYPE_COMPUTE_LIST;
-}
-
-void RenderingDeviceD3D12::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-	const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline);
-	ERR_FAIL_NULL(pipeline);
-
-	if (p_compute_pipeline == cl->state.pipeline) {
-		return; // Redundant state, return.
-	}
-
-	cl->state.pipeline = p_compute_pipeline;
-	cl->state.pso = pipeline->pso.Get();
-
-	Shader *shader = shader_owner.get_or_null(pipeline->shader);
-
-	if (cl->state.pipeline_shader != pipeline->shader) {
-		if (cl->state.root_signature_crc != pipeline->root_signature_crc) {
-			cl->command_list->SetComputeRootSignature(shader->root_signature.Get());
-			cl->state.root_signature_crc = pipeline->root_signature_crc;
-			// Root signature changed, so current descriptor set bindings become invalid.
-			for (uint32_t i = 0; i < cl->state.set_count; i++) {
-				cl->state.sets[i].bound = false;
-			}
-		}
-
-		const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
-		cl->state.set_count = pipeline->set_formats.size(); // Update set count.
-		for (uint32_t i = 0; i < cl->state.set_count; i++) {
-			cl->state.sets[i].pipeline_expected_format = pformats[i];
-#ifdef DEV_ENABLED
-			cl->state.sets[i]._pipeline_expected_format = pformats[i] ? &uniform_set_format_cache_reverse[pformats[i] - 1]->key().uniform_info : nullptr;
-#endif
-		}
-
-		if (pipeline->spirv_push_constant_size) {
-#ifdef DEBUG_ENABLED
-			cl->validation.pipeline_push_constant_supplied = false;
-#endif
-		}
-
-		cl->state.pipeline_shader = pipeline->shader;
-		cl->state.pipeline_dxil_push_constant_size = pipeline->dxil_push_constant_size;
-		cl->state.pipeline_bindings_id = pipeline->bindings_id;
-		cl->state.local_group_size[0] = pipeline->local_group_size[0];
-		cl->state.local_group_size[1] = pipeline->local_group_size[1];
-		cl->state.local_group_size[2] = pipeline->local_group_size[2];
-#ifdef DEV_ENABLED
-		cl->state._shader = shader;
-#endif
-	}
-
-#ifdef DEBUG_ENABLED
-	// Update compute pass pipeline info.
-	cl->validation.pipeline_active = true;
-	cl->validation.pipeline_spirv_push_constant_size = pipeline->spirv_push_constant_size;
-#endif
-}
-
-void RenderingDeviceD3D12::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-	UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(uniform_set);
-
-	if (p_index > cl->state.set_count) {
-		cl->state.set_count = p_index;
-	}
-
-	cl->state.sets[p_index].bound = false; // Needs rebind.
-	cl->state.sets[p_index].uniform_set_format = uniform_set->format;
-	cl->state.sets[p_index].uniform_set = p_uniform_set;
-#ifdef DEV_ENABLED
-	cl->state.sets[p_index]._uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-#endif
-}
-
-void RenderingDeviceD3D12::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_spirv_push_constant_size,
-			"This render pipeline requires (" + itos(cl->validation.pipeline_spirv_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
-#endif
-	if (cl->state.pipeline_dxil_push_constant_size) {
-		cl->command_list->SetComputeRoot32BitConstants(0, p_data_size / sizeof(uint32_t), p_data, 0);
-	}
-#ifdef DEBUG_ENABLED
-	cl->validation.pipeline_push_constant_supplied = true;
-#endif
-}
-
-void RenderingDeviceD3D12::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_x_groups == 0, "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_z_groups == 0, "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_y_groups == 0, "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_x_groups > D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
-			"Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION) + ")");
-	ERR_FAIL_COND_MSG(p_y_groups > D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
-			"Dispatch amount of Y compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION) + ")");
-	ERR_FAIL_COND_MSG(p_z_groups > D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
-			"Dispatch amount of Z compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION) + ")");
-
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_spirv_push_constant_size) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	// Bind descriptor sets.
-	Shader *shader = shader_owner.get_or_null(cl->state.pipeline_shader);
-	struct SetToBind {
-		uint32_t set;
-		UniformSet *uniform_set;
-		const Shader::Set *shader_set;
-	};
-	SetToBind *sets_to_bind = (SetToBind *)alloca(sizeof(SetToBind) * cl->state.set_count);
-	uint32_t num_sets_to_bind = 0;
-	for (uint32_t i = 0; i < cl->state.set_count; i++) {
-		if (cl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
-			if (cl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			}
-		}
-#endif
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-		const Shader::Set &shader_set = shader->sets[i];
-		_apply_uniform_set_resource_states(uniform_set, shader_set);
-		if (!cl->state.sets[i].bound) {
-			sets_to_bind[num_sets_to_bind].set = i;
-			sets_to_bind[num_sets_to_bind].uniform_set = uniform_set;
-			sets_to_bind[num_sets_to_bind].shader_set = &shader_set;
-			num_sets_to_bind++;
-			cl->state.sets[i].bound = true;
-		}
-	}
-
-	_resource_transitions_flush(cl->command_list);
-
-	for (uint32_t i = 0; i < num_sets_to_bind; i++) {
-		_bind_uniform_set(sets_to_bind[i].uniform_set, *sets_to_bind[i].shader_set, pipeline_bindings[cl->state.pipeline_bindings_id][sets_to_bind[i].set], cl->command_list, true);
-	}
-
-	if (cl->state.bound_pso != cl->state.pso) {
-		cl->command_list->SetPipelineState(cl->state.pso);
-		cl->state.bound_pso = cl->state.pso;
-	}
-	cl->command_list->Dispatch(p_x_groups, p_y_groups, p_z_groups);
-}
-
-void RenderingDeviceD3D12::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_y_threads == 0, "Dispatch amount of Y compute threads (" + itos(p_y_threads) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_z_threads == 0, "Dispatch amount of Z compute threads (" + itos(p_z_threads) + ") is zero.");
-#endif
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_spirv_push_constant_size) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	compute_list_dispatch(p_list, (p_x_threads - 1) / cl->state.local_group_size[0] + 1, (p_y_threads - 1) / cl->state.local_group_size[1] + 1, (p_z_threads - 1) / cl->state.local_group_size[2] + 1);
-}
-
-void RenderingDeviceD3D12::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-	Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);
-	ERR_FAIL_NULL(buffer);
-
-	ERR_FAIL_COND_MSG(!(buffer->usage & D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT), "Buffer provided was not created to do indirect dispatch.");
-
-	ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer.");
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_spirv_push_constant_size) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	// Bind descriptor sets.
-
-	Shader *shader = shader_owner.get_or_null(cl->state.pipeline_shader);
-	struct SetToBind {
-		uint32_t set;
-		UniformSet *uniform_set;
-		const Shader::Set *shader_set;
-	};
-	SetToBind *sets_to_bind = (SetToBind *)alloca(sizeof(SetToBind) * cl->state.set_count);
-	uint32_t num_sets_to_bind = 0;
-	for (uint32_t i = 0; i < cl->state.set_count; i++) {
-		if (cl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
-			if (cl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			}
-		}
-#endif
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-		const Shader::Set &shader_set = shader->sets[i];
-		_apply_uniform_set_resource_states(uniform_set, shader_set);
-		if (!cl->state.sets[i].bound) {
-			sets_to_bind[num_sets_to_bind].set = i;
-			sets_to_bind[num_sets_to_bind].uniform_set = uniform_set;
-			sets_to_bind[num_sets_to_bind].shader_set = &shader_set;
-			num_sets_to_bind++;
-			cl->state.sets[i].bound = true;
-		}
-	}
-
-	_resource_transition_batch(buffer, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
-
-	_resource_transitions_flush(cl->command_list);
-
-	for (uint32_t i = 0; i < num_sets_to_bind; i++) {
-		_bind_uniform_set(sets_to_bind[i].uniform_set, *sets_to_bind[i].shader_set, pipeline_bindings[cl->state.pipeline_bindings_id][sets_to_bind[i].set], cl->command_list, true);
-	}
-
-	if (cl->state.bound_pso != cl->state.pso) {
-		cl->command_list->SetPipelineState(cl->state.pso);
-		cl->state.bound_pso = cl->state.pso;
-	}
-	cl->command_list->ExecuteIndirect(indirect_dispatch_cmd_sig.Get(), 1, buffer->resource, p_offset, nullptr, 0);
-}
-
-void RenderingDeviceD3D12::compute_list_add_barrier(ComputeListID p_list) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-#ifdef FORCE_FULL_BARRIER
-	full_barrier();
-#else
-	// Due to D3D12 resource-wise barriers, this is no op.
-#endif
-}
-
-void RenderingDeviceD3D12::compute_list_end(BitField<BarrierMask> p_post_barrier) {
-	ERR_FAIL_NULL(compute_list);
-
-#ifdef FORCE_FULL_BARRIER
-	full_barrier();
-#endif
-
-	memdelete(compute_list);
-	compute_list = nullptr;
-}
-
-void RenderingDeviceD3D12::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
-	// Due to D3D12 resource-wise barriers, this is no op.
-}
-
-void RenderingDeviceD3D12::full_barrier() {
-#ifndef DEBUG_ENABLED
-	ERR_PRINT("Full barrier is debug-only, should not be used in production");
-#endif
-
-	// In the resource barriers world, we can force a full barrier by discarding some resource, as per
-	// https://microsoft.github.io/DirectX-Specs/d3d/D3D12EnhancedBarriers.html#synchronous-copy-discard-and-resolve.
-	frames[frame].draw_command_list->DiscardResource(texture_owner.get_or_null(aux_resource)->resource, nullptr);
-}
-
-void RenderingDeviceD3D12::_free_internal(RID p_id) {
-#ifdef DEV_ENABLED
-	String resource_name;
-	if (resource_names.has(p_id)) {
-		resource_name = resource_names[p_id];
-		resource_names.erase(p_id);
-	}
-#endif
-
-	// Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).
-	if (texture_owner.owns(p_id)) {
-		Texture *texture = texture_owner.get_or_null(p_id);
-		frames[frame].textures_to_dispose_of.push_back(*texture);
-		texture_owner.free(p_id);
-	} else if (framebuffer_owner.owns(p_id)) {
-		Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
-		frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);
-
-		if (framebuffer->invalidated_callback != nullptr) {
-			framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);
-		}
-		framebuffer_owner.free(p_id);
-	} else if (sampler_owner.owns(p_id)) {
-		sampler_owner.free(p_id);
-	} else if (vertex_buffer_owner.owns(p_id)) {
-		Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer);
-		vertex_buffer_owner.free(p_id);
-	} else if (vertex_array_owner.owns(p_id)) {
-		vertex_array_owner.free(p_id);
-	} else if (index_buffer_owner.owns(p_id)) {
-		IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*index_buffer);
-		index_buffer_owner.free(p_id);
-	} else if (index_array_owner.owns(p_id)) {
-		index_array_owner.free(p_id);
-	} else if (shader_owner.owns(p_id)) {
-		Shader *shader = shader_owner.get_or_null(p_id);
-		frames[frame].shaders_to_dispose_of.push_back(*shader);
-		shader_owner.free(p_id);
-	} else if (uniform_buffer_owner.owns(p_id)) {
-		Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer);
-		uniform_buffer_owner.free(p_id);
-	} else if (texture_buffer_owner.owns(p_id)) {
-		TextureBuffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(texture_buffer->buffer);
-		texture_buffer_owner.free(p_id);
-	} else if (storage_buffer_owner.owns(p_id)) {
-		Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);
-		storage_buffer_owner.free(p_id);
-	} else if (uniform_set_owner.owns(p_id)) {
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
-		uniform_set_owner.free(p_id);
-
-		if (uniform_set->invalidated_callback != nullptr) {
-			uniform_set->invalidated_callback(uniform_set->invalidated_callback_userdata);
-		}
-	} else if (render_pipeline_owner.owns(p_id)) {
-		RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);
-		frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline);
-		render_pipeline_owner.free(p_id);
-	} else if (compute_pipeline_owner.owns(p_id)) {
-		ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
-		frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);
-		compute_pipeline_owner.free(p_id);
-	} else {
-#ifdef DEV_ENABLED
-		ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);
-#else
-		ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));
-#endif
-	}
-}
-
-void RenderingDeviceD3D12::free(RID p_id) {
-	_THREAD_SAFE_METHOD_
-
-	_free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems.
-	_free_internal(p_id);
-}
-
-void RenderingDeviceD3D12::set_resource_name(RID p_id, const String p_name) {
-	if (texture_owner.owns(p_id)) {
-		Texture *texture = texture_owner.get_or_null(p_id);
-		// Don't set the source texture's name when calling on a texture view.
-		if (texture->owner.is_null()) {
-			context->set_object_name(texture->resource, p_name);
-		}
-	} else if (framebuffer_owner.owns(p_id)) {
-		// No D3D12 object to name.
-	} else if (sampler_owner.owns(p_id)) {
-		// No D3D12 object to name.
-	} else if (shader_owner.owns(p_id)) {
-		Shader *shader = shader_owner.get_or_null(p_id);
-		context->set_object_name(shader->root_signature.Get(), p_name + " Root Signature");
-	} else if (uniform_set_owner.owns(p_id)) {
-		// No D3D12 object to name.
-	} else if (render_pipeline_owner.owns(p_id)) {
-		RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);
-		context->set_object_name(pipeline->pso.Get(), p_name);
-	} else if (compute_pipeline_owner.owns(p_id)) {
-		ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
-		context->set_object_name(pipeline->pso.Get(), p_name);
-	} else {
-		Buffer *buffer = _get_buffer_from_owner(p_id);
-		if (buffer) {
-			context->set_object_name(buffer->resource, p_name);
-		} else {
-			ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));
-			return;
-		}
-	}
-#ifdef DEV_ENABLED
-	resource_names[p_id] = p_name;
-#endif
-}
-
-void RenderingDeviceD3D12::draw_command_begin_label(String p_label_name, const Color p_color) {
-	_THREAD_SAFE_METHOD_
-	context->command_begin_label(frames[frame].draw_command_list.Get(), p_label_name, p_color);
-}
-
-void RenderingDeviceD3D12::draw_command_insert_label(String p_label_name, const Color p_color) {
-	_THREAD_SAFE_METHOD_
-	context->command_insert_label(frames[frame].draw_command_list.Get(), p_label_name, p_color);
-}
-
-void RenderingDeviceD3D12::draw_command_end_label() {
-	_THREAD_SAFE_METHOD_
-	context->command_end_label(frames[frame].draw_command_list.Get());
-}
-
-String RenderingDeviceD3D12::get_device_vendor_name() const {
-	return context->get_device_vendor_name();
-}
-
-String RenderingDeviceD3D12::get_device_name() const {
-	return context->get_device_name();
-}
-
-RenderingDevice::DeviceType RenderingDeviceD3D12::get_device_type() const {
-	return context->get_device_type();
-}
-
-String RenderingDeviceD3D12::get_device_api_version() const {
-	return context->get_device_api_version();
-}
-
-String RenderingDeviceD3D12::get_device_pipeline_cache_uuid() const {
-	return context->get_device_pipeline_cache_uuid();
-}
-
-void RenderingDeviceD3D12::_finalize_command_bufers() {
-	if (draw_list) {
-		ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work).");
-	}
-
-	if (compute_list) {
-		ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
-	}
-
-	{ // Complete the setup buffer (that needs to be processed before anything else).
-		frames[frame].setup_command_list->Close();
-		frames[frame].draw_command_list->Close();
-	}
-}
-
-void RenderingDeviceD3D12::_begin_frame() {
-	// Erase pending resources.
-	_free_pending_resources(frame);
-
-	HRESULT res = frames[frame].setup_command_allocator->Reset();
-	ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-	res = frames[frame].setup_command_list->Reset(frames[frame].setup_command_allocator.Get(), nullptr);
-	ERR_FAIL_COND_MSG(res, "Command list Reset failed with error " + vformat("0x%08ux", res) + ".");
-	res = frames[frame].draw_command_allocator->Reset();
-	ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-	res = frames[frame].draw_command_list->Reset(frames[frame].draw_command_allocator.Get(), nullptr);
-	ERR_FAIL_COND_MSG(res, "Command list Reset failed with error " + vformat("0x%08ux", res) + ".");
-
-	ID3D12DescriptorHeap *heaps[] = {
-		frames[frame].desc_heaps.resources.get_heap(),
-		frames[frame].desc_heaps.samplers.get_heap(),
-	};
-	frames[frame].draw_command_list->SetDescriptorHeaps(2, heaps);
-
-	frames[frame].desc_heap_walkers.resources.rewind();
-	frames[frame].desc_heap_walkers.samplers.rewind();
-	frames[frame].desc_heap_walkers.aux.rewind();
-	frames[frame].desc_heap_walkers.rtv.rewind();
-	frames[frame].desc_heaps_exhausted_reported = {};
-	frames[frame].null_rtv_handle = {};
-
-#ifdef DEBUG_COUNT_BARRIERS
-	print_verbose(vformat("Last frame: %d barriers (%d batches); %.1f ms", frame_barriers_count, frame_barriers_batches_count, frame_barriers_cpu_time * 0.001f));
-	frame_barriers_count = 0;
-	frame_barriers_batches_count = 0;
-	frame_barriers_cpu_time = 0;
-#endif
-
-	if (local_device.is_null()) {
-		context->append_command_list(frames[frame].draw_command_list.Get());
-		context->set_setup_list(frames[frame].setup_command_list.Get()); // Append now so it's added before everything else.
-	}
-
-	// Advance current frame.
-	frames_drawn++;
-	// Advance staging buffer if used.
-	if (staging_buffer_used) {
-		staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
-		staging_buffer_used = false;
-	}
-
-	context->get_allocator()->SetCurrentFrameIndex(Engine::get_singleton()->get_frames_drawn());
-	if (frames[frame].timestamp_count) {
-		frames[frame].setup_command_list->ResolveQueryData(frames[frame].timestamp_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 0, frames[frame].timestamp_count, frames[frame].timestamp_result_values_buffer.resource, 0);
-		uint64_t *gpu_timestamps = nullptr;
-		res = frames[frame].timestamp_result_values_buffer.resource->Map(0, nullptr, (void **)&gpu_timestamps);
-		if (SUCCEEDED(res)) {
-			memcpy(frames[frame].timestamp_result_values.ptr(), gpu_timestamps, sizeof(uint64_t) * frames[frame].timestamp_count);
-			frames[frame].timestamp_result_values_buffer.resource->Unmap(0, nullptr);
-		}
-		SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
-		SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
-	}
-
-	frames[frame].timestamp_result_count = frames[frame].timestamp_count;
-	frames[frame].timestamp_count = 0;
-	frames[frame].index = Engine::get_singleton()->get_frames_drawn();
-	frames[frame].execution_index = execution_index;
-#ifdef DEV_ENABLED
-	frames[frame].uniform_set_reused = 0;
-#endif
-}
-
-void RenderingDeviceD3D12::swap_buffers() {
-	ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers.");
-	_THREAD_SAFE_METHOD_
-
-	context->postpare_buffers(frames[frame].draw_command_list.Get());
-	screen_prepared = false;
-
-	_finalize_command_bufers();
-
-	context->swap_buffers();
-	execution_index++;
-
-	frame = (frame + 1) % frame_count;
-
-	_begin_frame();
-}
-
-void RenderingDeviceD3D12::submit() {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
-	ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");
-
-	_finalize_command_bufers();
-
-	ID3D12CommandList *command_lists[2] = { frames[frame].setup_command_list.Get(), frames[frame].draw_command_list.Get() };
-	context->local_device_push_command_lists(local_device, command_lists, 2);
-	execution_index++;
-
-	local_device_processing = true;
-}
-
-void RenderingDeviceD3D12::sync() {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
-	ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");
-
-	context->local_device_sync(local_device);
-	_begin_frame();
-	local_device_processing = false;
-}
-
-#ifdef USE_SMALL_ALLOCS_POOL
-D3D12MA::Pool *RenderingDeviceD3D12::_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags) {
-	D3D12_HEAP_FLAGS effective_heap_flags = p_heap_flags;
-	if (context->get_allocator()->GetD3D12Options().ResourceHeapTier != D3D12_RESOURCE_HEAP_TIER_1) {
-		// Heap tier 2 allows mixing resource types liberally.
-		effective_heap_flags &= ~(D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS | D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES);
-	}
-
-	AllocPoolKey pool_key;
-	pool_key.heap_type = p_heap_type;
-	pool_key.heap_flags = effective_heap_flags;
-	if (small_allocs_pools.has(pool_key.key)) {
-		return small_allocs_pools[pool_key.key].Get();
-	}
-
-#ifdef DEV_ENABLED
-	print_verbose("Creating D3D12MA small objects pool for heap type " + itos(p_heap_type) + " and heap flags " + itos(p_heap_flags));
-#endif
-
-	D3D12MA::POOL_DESC poolDesc = {};
-	poolDesc.HeapProperties.Type = p_heap_type;
-	poolDesc.HeapFlags = effective_heap_flags;
-
-	ComPtr<D3D12MA::Pool> pool;
-	HRESULT res = context->get_allocator()->CreatePool(&poolDesc, pool.GetAddressOf());
-	small_allocs_pools[pool_key.key] = pool; // Don't try to create it again if failed the first time.
-	ERR_FAIL_COND_V_MSG(res, nullptr, "CreatePool failed with error " + vformat("0x%08ux", res) + ".");
-
-	return pool.Get();
-}
-#endif
-
-void RenderingDeviceD3D12::_free_pending_resources(int p_frame) {
-	// Free in dependency usage order, so nothing weird happens.
-	// Pipelines.
-	while (frames[p_frame].render_pipelines_to_dispose_of.front()) {
-		RenderPipeline *rp = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();
-		pipeline_bindings.erase(rp->bindings_id);
-		frames[p_frame].render_pipelines_to_dispose_of.pop_front();
-	}
-	while (frames[p_frame].compute_pipelines_to_dispose_of.front()) {
-		ComputePipeline *cp = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get();
-		pipeline_bindings.erase(cp->bindings_id);
-		frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
-	}
-
-	// Shaders.
-	frames[p_frame].shaders_to_dispose_of.clear();
-
-	// Framebuffers.
-	frames[p_frame].framebuffers_to_dispose_of.clear();
-
-	// Textures.
-	while (frames[p_frame].textures_to_dispose_of.front()) {
-		Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
-
-		if (texture->bound) {
-			WARN_PRINT("Deleted a texture while it was bound.");
-		}
-		if (texture->owner.is_null()) {
-			// Actually owns the image and the allocation too.
-			image_memory -= texture->allocation->GetSize();
-			for (uint32_t i = 0; i < texture->aliases.size(); i++) {
-				if (texture->aliases[i]) {
-					texture->aliases[i]->Release();
-				}
-			}
-			texture->resource->Release();
-			texture->resource = nullptr;
-			texture->allocation->Release();
-			texture->allocation = nullptr;
-		}
-		frames[p_frame].textures_to_dispose_of.pop_front();
-	}
-
-	// Buffers.
-	while (frames[p_frame].buffers_to_dispose_of.front()) {
-		_buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get());
-
-		frames[p_frame].buffers_to_dispose_of.pop_front();
-	}
-}
-
-void RenderingDeviceD3D12::prepare_screen_for_drawing() {
-	_THREAD_SAFE_METHOD_
-	context->prepare_buffers(frames[frame].draw_command_list.Get());
-	screen_prepared = true;
-}
-
-uint32_t RenderingDeviceD3D12::get_frame_delay() const {
-	return frame_count;
-}
-
-uint64_t RenderingDeviceD3D12::get_memory_usage(MemoryType p_type) const {
-	if (p_type == MEMORY_BUFFERS) {
-		return buffer_memory;
-	} else if (p_type == MEMORY_TEXTURES) {
-		return image_memory;
-	} else {
-		D3D12MA::TotalStatistics stats;
-		context->get_allocator()->CalculateStatistics(&stats);
-		return stats.Total.Stats.BlockBytes;
-	}
-}
-
-void RenderingDeviceD3D12::_flush(bool p_flush_current_frame) {
-	if (local_device.is_valid() && !p_flush_current_frame) {
-		return; // Flushing previous frames has no effect with local device.
-	}
-
-	if (p_flush_current_frame) {
-		frames[frame].setup_command_list->Close();
-		frames[frame].draw_command_list->Close();
-	}
-
-	if (local_device.is_valid()) {
-		ID3D12CommandList *command_lists[2] = { frames[frame].setup_command_list.Get(), frames[frame].draw_command_list.Get() };
-		context->local_device_push_command_lists(local_device, command_lists, 2);
-		execution_index++;
-		context->local_device_sync(local_device);
-
-		HRESULT res = frames[frame].setup_command_allocator->Reset();
-		ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-		res = frames[frame].setup_command_list->Reset(frames[frame].setup_command_allocator.Get(), nullptr);
-		ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-		res = frames[frame].draw_command_allocator->Reset();
-		ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-		res = frames[frame].draw_command_list->Reset(frames[frame].draw_command_allocator.Get(), nullptr);
-		ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-
-		ID3D12DescriptorHeap *heaps[] = {
-			frames[frame].desc_heaps.resources.get_heap(),
-			frames[frame].desc_heaps.samplers.get_heap(),
-		};
-		frames[frame].draw_command_list->SetDescriptorHeaps(2, heaps);
-		frames[frame].desc_heap_walkers.resources.rewind();
-		frames[frame].desc_heap_walkers.samplers.rewind();
-		frames[frame].desc_heap_walkers.aux.rewind();
-		frames[frame].desc_heap_walkers.rtv.rewind();
-		frames[frame].desc_heaps_exhausted_reported = {};
-		frames[frame].null_rtv_handle = {};
-		frames[frame].execution_index = execution_index;
-	} else {
-		context->flush(p_flush_current_frame, p_flush_current_frame);
-		// Re-create the setup command.
-		if (p_flush_current_frame) {
-			execution_index++;
-
-			HRESULT res = frames[frame].setup_command_allocator->Reset();
-			ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-			res = frames[frame].draw_command_allocator->Reset();
-			ERR_FAIL_COND_MSG(res, "Command allocator Reset failed with error " + vformat("0x%08ux", res) + ".");
-			res = frames[frame].setup_command_list->Reset(frames[frame].setup_command_allocator.Get(), nullptr);
-			ERR_FAIL_COND_MSG(res, "Command list Reset failed with error " + vformat("0x%08ux", res) + ".");
-			res = frames[frame].draw_command_list->Reset(frames[frame].draw_command_allocator.Get(), nullptr);
-			ERR_FAIL_COND_MSG(res, "Command list Reset failed with error " + vformat("0x%08ux", res) + ".");
-
-			ID3D12DescriptorHeap *heaps[] = {
-				frames[frame].desc_heaps.resources.get_heap(),
-				frames[frame].desc_heaps.samplers.get_heap(),
-			};
-			frames[frame].draw_command_list->SetDescriptorHeaps(2, heaps);
-
-			frames[frame].desc_heap_walkers.resources.rewind();
-			frames[frame].desc_heap_walkers.samplers.rewind();
-			frames[frame].desc_heap_walkers.aux.rewind();
-			frames[frame].desc_heap_walkers.rtv.rewind();
-			frames[frame].desc_heaps_exhausted_reported = {};
-			frames[frame].null_rtv_handle = {};
-			frames[frame].execution_index = execution_index;
-
-			context->set_setup_list(frames[frame].setup_command_list.Get()); // Append now so it's added before everything else.
-			context->append_command_list(frames[frame].draw_command_list.Get());
-		}
-	}
-}
-
-void RenderingDeviceD3D12::initialize(D3D12Context *p_context, bool p_local_device) {
-	// Get our device capabilities.
-	{
-		device_capabilities.version_major = p_context->get_feat_level_major();
-		device_capabilities.version_minor = p_context->get_feat_level_minor();
-	}
-
-	context = p_context;
-	device = p_context->get_device();
-	if (p_local_device) {
-		frame_count = 1;
-		local_device = p_context->local_device_create();
-		device = p_context->local_device_get_d3d12_device(local_device);
-	} else {
-		frame_count = p_context->get_swapchain_image_count() + 1;
-	}
-	limits = p_context->get_device_limits();
-	max_timestamp_query_elements = 256;
-
-	{ // Create command signature for indirect dispatch.
-		D3D12_INDIRECT_ARGUMENT_DESC iarg_desc = {};
-		iarg_desc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
-		D3D12_COMMAND_SIGNATURE_DESC cs_desc = {};
-		cs_desc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS);
-		cs_desc.NumArgumentDescs = 1;
-		cs_desc.pArgumentDescs = &iarg_desc;
-		cs_desc.NodeMask = 0;
-		HRESULT res = device->CreateCommandSignature(&cs_desc, nullptr, IID_PPV_ARGS(indirect_dispatch_cmd_sig.GetAddressOf()));
-		ERR_FAIL_COND_MSG(res, "CreateCommandSignature failed with error " + vformat("0x%08ux", res) + ".");
-	}
-
-	uint32_t resource_descriptors_per_frame = GLOBAL_DEF("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", 16384);
-	uint32_t sampler_descriptors_per_frame = GLOBAL_DEF("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", 1024);
-	uint32_t misc_descriptors_per_frame = GLOBAL_DEF("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", 512);
-
-	frames.resize(frame_count);
-	frame = 0;
-	// Create setup and frame buffers.
-	for (int i = 0; i < frame_count; i++) {
-		frames[i].index = 0;
-
-		{ // Create descriptor heaps.
-			Error err = frames[i].desc_heaps.resources.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, resource_descriptors_per_frame, true);
-			ERR_FAIL_COND_MSG(err, "Creating the frame's RESOURCE descriptors heap failed.");
-
-			err = frames[i].desc_heaps.samplers.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, sampler_descriptors_per_frame, true);
-			ERR_FAIL_COND_MSG(err, "Creating the frame's SAMPLER descriptors heap failed.");
-
-			err = frames[i].desc_heaps.aux.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, misc_descriptors_per_frame, false);
-			ERR_FAIL_COND_MSG(err, "Creating the frame's AUX descriptors heap failed.");
-
-			err = frames[i].desc_heaps.rtv.allocate(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, misc_descriptors_per_frame, false);
-			ERR_FAIL_COND_MSG(err, "Creating the frame's RENDER TARGET descriptors heap failed.");
-
-			frames[i].desc_heap_walkers.resources = frames[i].desc_heaps.resources.make_walker();
-			frames[i].desc_heap_walkers.samplers = frames[i].desc_heaps.samplers.make_walker();
-			frames[i].desc_heap_walkers.aux = frames[i].desc_heaps.aux.make_walker();
-			frames[i].desc_heap_walkers.rtv = frames[i].desc_heaps.rtv.make_walker();
-		}
-
-		{ // Create command allocators.
-			HRESULT res = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frames[i].setup_command_allocator.GetAddressOf()));
-			ERR_CONTINUE_MSG(res, "CreateCommandAllocator failed with error " + vformat("0x%08ux", res) + ".");
-
-			res = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frames[i].draw_command_allocator.GetAddressOf()));
-			ERR_CONTINUE_MSG(res, "CreateCommandAllocator failed with error " + vformat("0x%08ux", res) + ".");
-		}
-
-		{ // Create command lists.
-			HRESULT res = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frames[i].setup_command_allocator.Get(), nullptr, IID_PPV_ARGS(frames[i].setup_command_list.GetAddressOf()));
-			ERR_CONTINUE_MSG(res, "CreateCommandList failed with error " + vformat("0x%08ux", res) + ".");
-
-			res = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frames[i].draw_command_allocator.Get(), nullptr, IID_PPV_ARGS(frames[i].draw_command_list.GetAddressOf()));
-			ERR_CONTINUE_MSG(res, "CreateCommandList failed with error " + vformat("0x%08ux", res) + ".");
-
-			if (i > 0) {
-				frames[i].setup_command_list->Close();
-				frames[i].draw_command_list->Close();
-			}
-		}
-
-		if (i == 0) {
-			ID3D12DescriptorHeap *heaps[] = {
-				frames[frame].desc_heaps.resources.get_heap(),
-				frames[frame].desc_heaps.samplers.get_heap(),
-			};
-			frames[frame].draw_command_list->SetDescriptorHeaps(2, heaps);
-		}
-
-		{
-			// Create query heap.
-			D3D12_QUERY_HEAP_DESC qh_desc = {};
-			qh_desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
-			qh_desc.Count = max_timestamp_query_elements;
-			qh_desc.NodeMask = 0;
-			HRESULT res = device->CreateQueryHeap(&qh_desc, IID_PPV_ARGS(frames[i].timestamp_heap.GetAddressOf()));
-			ERR_CONTINUE_MSG(res, "CreateQueryHeap failed with error " + vformat("0x%08ux", res) + ".");
-
-			frames[i].timestamp_names.resize(max_timestamp_query_elements);
-			frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);
-			frames[i].timestamp_count = 0;
-			frames[i].timestamp_result_names.resize(max_timestamp_query_elements);
-			frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);
-			frames[i].timestamp_result_values.resize(max_timestamp_query_elements);
-			Error err = _buffer_allocate(&frames[i].timestamp_result_values_buffer, sizeof(uint64_t) * max_timestamp_query_elements, D3D12_RESOURCE_STATE_COMMON, D3D12_HEAP_TYPE_READBACK);
-			ERR_CONTINUE(err);
-			frames[i].timestamp_result_count = 0;
-		}
-	}
-
-	if (local_device.is_null()) {
-		context->set_setup_list(frames[0].setup_command_list.Get()); // Append now so it's added before everything else.
-		context->append_command_list(frames[0].draw_command_list.Get());
-	}
-
-	staging_buffer_block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");
-	staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
-	staging_buffer_block_size *= 1024; // Kb -> bytes.
-	staging_buffer_max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");
-	staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
-	staging_buffer_max_size *= 1024 * 1024;
-
-	if (staging_buffer_max_size < staging_buffer_block_size * 4) {
-		// Validate enough functions.
-		staging_buffer_max_size = staging_buffer_block_size * 4;
-	}
-	texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");
-	texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
-
-	frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
-	execution_index = 1;
-
-	// Ensure current staging block is valid and at least one per frame exists.
-	staging_buffer_current = 0;
-	staging_buffer_used = false;
-
-	for (int i = 0; i < frame_count; i++) {
-		// Staging was never used, create a block.
-		Error err = _insert_staging_block();
-		ERR_CONTINUE(err != OK);
-	}
-
-	{
-		aux_resource = texture_create(TextureFormat(), TextureView());
-		ERR_FAIL_COND(!aux_resource.is_valid());
-	}
-
-	draw_list = nullptr;
-	draw_list_count = 0;
-	draw_list_split = false;
-
-	vrs_state_execution_index = 0;
-	vrs_state = {};
-
-	compute_list = nullptr;
-
-	glsl_type_singleton_init_or_ref();
-}
-
-dxil_validator *RenderingDeviceD3D12::get_dxil_validator_for_current_thread() {
-	MutexLock lock(dxil_mutex);
-
-	int thread_idx = WorkerThreadPool::get_singleton()->get_thread_index();
-	if (dxil_validators.has(thread_idx)) {
-		return dxil_validators[thread_idx];
-	}
-
-#ifdef DEV_ENABLED
-	print_verbose("Creating DXIL validator for worker thread index " + itos(thread_idx));
-#endif
-
-	dxil_validator *dxil_validator = dxil_create_validator(nullptr);
-	CRASH_COND(!dxil_validator);
-
-	dxil_validators.insert(thread_idx, dxil_validator);
-	return dxil_validator;
-}
-
-template <class T>
-void RenderingDeviceD3D12::_free_rids(T &p_owner, const char *p_type) {
-	List<RID> owned;
-	p_owner.get_owned_list(&owned);
-	if (owned.size()) {
-		if (owned.size() == 1) {
-			WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
-		} else {
-			WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
-		}
-		for (const RID &E : owned) {
-#ifdef DEV_ENABLED
-			if (resource_names.has(E)) {
-				print_line(String(" - ") + resource_names[E]);
-			}
-#endif
-			free(E);
-		}
-	}
-}
-
-void RenderingDeviceD3D12::capture_timestamp(const String &p_name) {
-	ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
-	ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
-
-	// This should be optional for profiling, else it will slow things down.
-	full_barrier();
-
-	frames[frame].draw_command_list->EndQuery(frames[frame].timestamp_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, frames[frame].timestamp_count);
-	frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
-	frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
-	frames[frame].timestamp_count++;
-}
-
-uint64_t RenderingDeviceD3D12::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) {
-	_THREAD_SAFE_METHOD_
-	return 0;
-}
-
-uint32_t RenderingDeviceD3D12::get_captured_timestamps_count() const {
-	return frames[frame].timestamp_result_count;
-}
-
-uint64_t RenderingDeviceD3D12::get_captured_timestamps_frame() const {
-	return frames[frame].index;
-}
-
-uint64_t RenderingDeviceD3D12::get_captured_timestamp_gpu_time(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
-
-	return frames[frame].timestamp_result_values[p_index] / (double)limits.timestamp_frequency * 1000000000.0;
-}
-
-uint64_t RenderingDeviceD3D12::get_captured_timestamp_cpu_time(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
-	return frames[frame].timestamp_cpu_result_values[p_index];
-}
-
-String RenderingDeviceD3D12::get_captured_timestamp_name(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
-	return frames[frame].timestamp_result_names[p_index];
-}
-
-uint64_t RenderingDeviceD3D12::limit_get(Limit p_limit) const {
-	switch (p_limit) {
-		case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:
-			return limits.max_srvs_per_shader_stage;
-		case LIMIT_MAX_UNIFORM_BUFFER_SIZE:
-			return 65536;
-		case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
-		case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
-			return 16384; // Based on max. texture size. Maybe not correct.
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:
-			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:
-			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:
-			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:
-			return D3D12_CS_THREAD_GROUP_MAX_X;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:
-			return D3D12_CS_THREAD_GROUP_MAX_Y;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
-			return D3D12_CS_THREAD_GROUP_MAX_Z;
-		case LIMIT_SUBGROUP_SIZE:
-		// Note in min/max. Shader model 6.6 supports it (see https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_WaveSize.html),
-		// but at this time I don't know the implications on the transpilation to DXIL, etc.
-		case LIMIT_SUBGROUP_MIN_SIZE:
-		case LIMIT_SUBGROUP_MAX_SIZE: {
-			D3D12Context::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.size;
-		}
-		case LIMIT_SUBGROUP_IN_SHADERS: {
-			D3D12Context::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.supported_stages_flags_rd();
-		}
-		case LIMIT_SUBGROUP_OPERATIONS: {
-			D3D12Context::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.supported_operations_flags_rd();
-		}
-		case LIMIT_VRS_TEXEL_WIDTH:
-		case LIMIT_VRS_TEXEL_HEIGHT: {
-			return context->get_vrs_capabilities().ss_image_tile_size;
-		}
-		default:
-			// It's important to return a number that at least won't overflow any typical integer type.
-#ifdef DEV_ENABLED
-			WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");
-#endif
-			return (uint64_t)1 << 30;
-	}
-}
-
-bool RenderingDeviceD3D12::has_feature(const Features p_feature) const {
-	switch (p_feature) {
-		case SUPPORTS_MULTIVIEW: {
-			D3D12Context::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities();
-			return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
-		} break;
-		case SUPPORTS_FSR_HALF_FLOAT: {
-			return context->get_shader_capabilities().native_16bit_ops && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
-		} break;
-		case SUPPORTS_ATTACHMENT_VRS: {
-			D3D12Context::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
-			return vrs_capabilities.ss_image_supported;
-		} break;
-		case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: {
-			return true;
-		} break;
-		default: {
-			return false;
-		}
-	}
-}
-
-void RenderingDeviceD3D12::finalize() {
-	// Free all resources.
-
-	_flush(false);
-
-	free(aux_resource);
-
-	_free_rids(render_pipeline_owner, "Pipeline");
-	_free_rids(compute_pipeline_owner, "Compute");
-	_free_rids(uniform_set_owner, "UniformSet");
-	_free_rids(texture_buffer_owner, "TextureBuffer");
-	_free_rids(storage_buffer_owner, "StorageBuffer");
-	_free_rids(uniform_buffer_owner, "UniformBuffer");
-	_free_rids(shader_owner, "Shader");
-	_free_rids(index_array_owner, "IndexArray");
-	_free_rids(index_buffer_owner, "IndexBuffer");
-	_free_rids(vertex_array_owner, "VertexArray");
-	_free_rids(vertex_buffer_owner, "VertexBuffer");
-	_free_rids(framebuffer_owner, "Framebuffer");
-	_free_rids(sampler_owner, "Sampler");
-	{
-		// For textures it's a bit more difficult because they may be shared.
-		List<RID> owned;
-		texture_owner.get_owned_list(&owned);
-		if (owned.size()) {
-			if (owned.size() == 1) {
-				WARN_PRINT("1 RID of type \"Texture\" was leaked.");
-			} else {
-				WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
-			}
-			// Free shared first.
-			for (List<RID>::Element *E = owned.front(); E;) {
-				List<RID>::Element *N = E->next();
-				if (texture_is_shared(E->get())) {
-#ifdef DEV_ENABLED
-					if (resource_names.has(E->get())) {
-						print_line(String(" - ") + resource_names[E->get()]);
-					}
-#endif
-					free(E->get());
-					owned.erase(E);
-				}
-				E = N;
-			}
-			// Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
-			for (const RID &E : owned) {
-#ifdef DEV_ENABLED
-				if (resource_names.has(E)) {
-					print_line(String(" - ") + resource_names[E]);
-				}
-#endif
-				free(E);
-			}
-		}
-	}
-
-	// Free everything pending.
-	for (int i = 0; i < frame_count; i++) {
-		int f = (frame + i) % frame_count;
-		_free_pending_resources(f);
-		frames[i].timestamp_result_values_buffer.allocation->Release();
-		frames[i].timestamp_result_values_buffer.resource->Release();
-	}
-
-	frames.clear();
-
-	pipeline_bindings.clear();
-	next_pipeline_binding_id = 1;
-
-	for (int i = 0; i < split_draw_list_allocators.size(); i++) {
-		for (int j = 0; i < split_draw_list_allocators[i].command_lists.size(); j++) {
-			split_draw_list_allocators[i].command_lists[j]->Release();
-		}
-		split_draw_list_allocators[i].command_allocator->Release();
-	}
-
-	res_barriers_requests.clear();
-	res_barriers.clear();
-
-	for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-		staging_buffer_blocks[i].allocation->Release();
-		staging_buffer_blocks[i].resource->Release();
-	}
-#ifdef USE_SMALL_ALLOCS_POOL
-	small_allocs_pools.clear();
-#endif
-
-	indirect_dispatch_cmd_sig.Reset();
-
-	vertex_formats.clear();
-
-	framebuffer_formats.clear();
-
-	// All these should be clear at this point.
-	ERR_FAIL_COND(dependency_map.size());
-	ERR_FAIL_COND(reverse_dependency_map.size());
-
-	{
-		MutexLock lock(dxil_mutex);
-		for (const KeyValue<int, dxil_validator *> &E : dxil_validators) {
-			dxil_destroy_validator(E.value);
-		}
-	}
-
-	glsl_type_singleton_decref();
-}
-
-RenderingDevice *RenderingDeviceD3D12::create_local_device() {
-	RenderingDeviceD3D12 *rd = memnew(RenderingDeviceD3D12);
-	rd->initialize(context, true);
-	return rd;
-}
-
-RenderingDeviceD3D12::RenderingDeviceD3D12() {
-	device_capabilities.device_family = DEVICE_DIRECTX;
-}
-
-RenderingDeviceD3D12::~RenderingDeviceD3D12() {
-	if (local_device.is_valid()) {
-		finalize();
-		context->local_device_free(local_device);
-	}
-}

+ 0 - 1277
drivers/d3d12/rendering_device_d3d12.h

@@ -1,1277 +0,0 @@
-/**************************************************************************/
-/*  rendering_device_d3d12.h                                              */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#ifndef RENDERING_DEVICE_D3D12_H
-#define RENDERING_DEVICE_D3D12_H
-
-#include "core/os/thread_safe.h"
-#include "core/templates/local_vector.h"
-#include "core/templates/oa_hash_map.h"
-#include "core/templates/rid_owner.h"
-#include "drivers/d3d12/d3d12_context.h"
-#include "servers/rendering/rendering_device.h"
-
-#include <wrl/client.h>
-
-using Microsoft::WRL::ComPtr;
-
-#define D3D12_BITCODE_OFFSETS_NUM_STAGES 3
-
-struct dxil_validator;
-
-class RenderingDeviceD3D12 : public RenderingDevice {
-	_THREAD_SAFE_CLASS_
-	// Miscellaneous tables that map
-	// our enums to enums used
-	// by DXGI/D3D12.
-
-	D3D12Context::DeviceLimits limits = {};
-	struct D3D12Format {
-		DXGI_FORMAT family = DXGI_FORMAT_UNKNOWN;
-		DXGI_FORMAT general_format = DXGI_FORMAT_UNKNOWN;
-		UINT swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
-		DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN;
-	};
-	static const D3D12Format d3d12_formats[DATA_FORMAT_MAX];
-	static const char *named_formats[DATA_FORMAT_MAX];
-	static const D3D12_COMPARISON_FUNC compare_operators[COMPARE_OP_MAX];
-	static const D3D12_STENCIL_OP stencil_operations[STENCIL_OP_MAX];
-	static const UINT rasterization_sample_count[TEXTURE_SAMPLES_MAX];
-	static const D3D12_LOGIC_OP logic_operations[RenderingDevice::LOGIC_OP_MAX];
-	static const D3D12_BLEND blend_factors[RenderingDevice::BLEND_FACTOR_MAX];
-	static const D3D12_BLEND_OP blend_operations[RenderingDevice::BLEND_OP_MAX];
-	static const D3D12_TEXTURE_ADDRESS_MODE address_modes[SAMPLER_REPEAT_MODE_MAX];
-	static const FLOAT sampler_border_colors[SAMPLER_BORDER_COLOR_MAX][4];
-	static const D3D12_RESOURCE_DIMENSION d3d12_texture_dimension[TEXTURE_TYPE_MAX];
-
-	// Functions used for format
-	// validation, and ensures the
-	// user passes valid data.
-
-	static int get_format_vertex_size(DataFormat p_format);
-	static uint32_t get_image_format_pixel_size(DataFormat p_format);
-	static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
-	uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
-	static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
-	static uint32_t get_image_format_plane_count(DataFormat p_format);
-	static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr);
-	static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
-	static bool format_has_stencil(DataFormat p_format);
-
-	Mutex dxil_mutex;
-	HashMap<int, dxil_validator *> dxil_validators; // One per WorkerThreadPool thread used for shader compilation, plus one (-1) for all the other.
-
-	dxil_validator *get_dxil_validator_for_current_thread();
-
-	class DescriptorsHeap {
-		D3D12_DESCRIPTOR_HEAP_DESC desc = {};
-		ComPtr<ID3D12DescriptorHeap> heap;
-		uint32_t handle_size = 0;
-
-	public:
-		class Walker { // Texas Ranger.
-			friend class DescriptorsHeap;
-
-			uint32_t handle_size = 0;
-			uint32_t handle_count = 0;
-			D3D12_CPU_DESCRIPTOR_HANDLE first_cpu_handle = {};
-			D3D12_GPU_DESCRIPTOR_HANDLE first_gpu_handle = {};
-			uint32_t handle_index = 0;
-
-		public:
-			D3D12_CPU_DESCRIPTOR_HANDLE get_curr_cpu_handle();
-			D3D12_GPU_DESCRIPTOR_HANDLE get_curr_gpu_handle();
-			_FORCE_INLINE_ void rewind() { handle_index = 0; }
-			void advance(uint32_t p_count = 1);
-			uint32_t get_current_handle_index() const { return handle_index; }
-			uint32_t get_free_handles() { return handle_count - handle_index; }
-			bool is_at_eof() { return handle_index == handle_count; }
-		};
-
-		Error allocate(ID3D12Device *m_device, D3D12_DESCRIPTOR_HEAP_TYPE m_type, uint32_t m_descriptor_count, bool p_for_gpu);
-		uint32_t get_descriptor_count() const { return desc.NumDescriptors; }
-		ID3D12DescriptorHeap *get_heap() const { return heap.Get(); }
-
-		Walker make_walker() const;
-	};
-
-	/***************************/
-	/**** ID INFRASTRUCTURE ****/
-	/***************************/
-
-	enum IDType {
-		ID_TYPE_FRAMEBUFFER_FORMAT,
-		ID_TYPE_VERTEX_FORMAT,
-		ID_TYPE_DRAW_LIST,
-		ID_TYPE_SPLIT_DRAW_LIST,
-		ID_TYPE_COMPUTE_LIST,
-		ID_TYPE_MAX,
-		ID_BASE_SHIFT = 58 // 5 bits for ID types.
-	};
-
-	ComPtr<ID3D12Device> device;
-
-	HashMap<RID, HashSet<RID>> dependency_map; // IDs to IDs that depend on it.
-	HashMap<RID, HashSet<RID>> reverse_dependency_map; // Same as above, but in reverse.
-
-	void _add_dependency(RID p_id, RID p_depends_on);
-	void _free_dependencies(RID p_id);
-
-	/******************/
-	/**** RESOURCE ****/
-	/******************/
-
-	class ResourceState {
-		D3D12_RESOURCE_STATES states = D3D12_RESOURCE_STATE_COMMON;
-
-	public:
-		void extend(D3D12_RESOURCE_STATES p_states_to_add);
-		D3D12_RESOURCE_STATES get_state_mask() const { return states; }
-
-		ResourceState() {}
-		ResourceState(D3D12_RESOURCE_STATES p_states) :
-				states(p_states) {}
-	};
-
-	struct Resource {
-		struct States {
-			// As many subresources as mipmaps * layers; planes (for depth-stencil) are tracked together.
-			LocalVector<D3D12_RESOURCE_STATES> subresource_states; // Used only if not a view.
-			uint32_t last_batch_transitioned_to_uav = 0;
-			uint32_t last_batch_with_uav_barrier = 0;
-		};
-
-		ID3D12Resource *resource = nullptr;
-		D3D12MA::Allocation *allocation = nullptr;
-
-		States own_states; // Used only if not a view.
-		States *states = nullptr; // Non-null only if a view.
-
-		States *get_states_ptr() { return states ? states : &own_states; }
-	};
-
-	struct BarrierRequest {
-		static const uint32_t MAX_GROUPS = 4;
-		// Maybe this is too much data to have it locally. Benchmarking may reveal that
-		// cache would be used better by having a maximum of local subresource masks and beyond
-		// that have an allocated vector with the rest.
-		static const uint32_t MAX_SUBRESOURCES = 4096; // Must be multiple of 64.
-		ID3D12Resource *dx_resource;
-		uint8_t subres_mask_qwords;
-		uint8_t planes;
-		struct Group {
-			ResourceState state;
-			uint64_t subres_mask[MAX_SUBRESOURCES / 64];
-		} groups[MAX_GROUPS];
-		uint8_t groups_count;
-		static const D3D12_RESOURCE_STATES DELETED_GROUP = D3D12_RESOURCE_STATE_COMMON;
-	};
-	HashMap<Resource::States *, BarrierRequest> res_barriers_requests;
-
-	LocalVector<D3D12_RESOURCE_BARRIER> res_barriers;
-	uint32_t res_barriers_count = 0;
-	uint32_t res_barriers_batch = 0;
-#ifdef DEV_ENABLED
-	int frame_barriers_count = 0;
-	int frame_barriers_batches_count = 0;
-	uint64_t frame_barriers_cpu_time = 0;
-#endif
-
-	void _resource_transition_batch(Resource *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override = nullptr);
-	void _resource_transitions_flush(ID3D12GraphicsCommandList *p_command_list);
-
-	/*****************/
-	/**** TEXTURE ****/
-	/*****************/
-
-	struct Texture : Resource {
-		D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
-		D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
-		D3D12_UNORDERED_ACCESS_VIEW_DESC owner_uav_desc = {}; // [[CROSS_FAMILY_ALIASING]].
-
-		TextureType type;
-		DataFormat format;
-		uint32_t planes = 1;
-		TextureSamples samples;
-		uint32_t width = 0;
-		uint32_t height = 0;
-		uint32_t depth = 0;
-		uint32_t layers = 0;
-		uint32_t mipmaps = 0;
-		uint32_t owner_layers = 0;
-		uint32_t owner_mipmaps = 0;
-		uint32_t usage_flags = 0;
-		uint32_t base_mipmap = 0;
-		uint32_t base_layer = 0;
-
-		Vector<DataFormat> allowed_shared_formats;
-		TightLocalVector<ID3D12Resource *> aliases; // [[CROSS_FAMILY_ALIASING]].
-		ID3D12Resource *owner_resource = nullptr; // Always the one of the main format passed to creation. [[CROSS_FAMILY_ALIASING]].
-
-		bool is_resolve_buffer = false;
-
-		bool bound = false; // Bound to framebffer.
-		RID owner;
-	};
-
-	RID_Owner<Texture, true> texture_owner;
-	uint32_t texture_upload_region_size_px = 0;
-
-	Vector<uint8_t> _texture_get_data_from_image(Texture *tex, uint32_t p_layer, bool p_2d = false);
-	Error _texture_update(Texture *p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, ID3D12GraphicsCommandList *p_command_list);
-
-	/*****************/
-	/**** SAMPLER ****/
-	/*****************/
-
-	RID_Owner<D3D12_SAMPLER_DESC> sampler_owner;
-
-	/***************************/
-	/**** BUFFER MANAGEMENT ****/
-	/***************************/
-
-	// These are temporary buffers on CPU memory that hold
-	// the information until the CPU fetches it and places it
-	// either on GPU buffers, or images (textures). It ensures
-	// updates are properly synchronized with whatever the
-	// GPU is doing.
-	//
-	// The logic here is as follows, only 3 of these
-	// blocks are created at the beginning (one per frame)
-	// they can each belong to a frame (assigned to current when
-	// used) and they can only be reused after the same frame is
-	// recycled.
-	//
-	// When CPU requires to allocate more than what is available,
-	// more of these buffers are created. If a limit is reached,
-	// then a fence will ensure will wait for blocks allocated
-	// in previous frames are processed. If that fails, then
-	// another fence will ensure everything pending for the current
-	// frame is processed (effectively stalling).
-	//
-	// See the comments in the code to understand better how it works.
-
-	struct StagingBufferBlock {
-		ID3D12Resource *resource = nullptr; // Owned, but ComPtr would have too much overhead in a Vector.
-		D3D12MA::Allocation *allocation = nullptr;
-		uint64_t frame_used = 0;
-		uint32_t fill_amount = 0;
-	};
-
-	Vector<StagingBufferBlock> staging_buffer_blocks;
-	int staging_buffer_current = 0;
-	uint32_t staging_buffer_block_size = 0;
-	uint64_t staging_buffer_max_size = 0;
-	bool staging_buffer_used = false;
-
-	Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true);
-	Error _insert_staging_block();
-
-	struct Buffer : Resource {
-		uint32_t size = 0;
-		D3D12_RESOURCE_STATES usage = {};
-		uint32_t last_execution = 0;
-	};
-
-	Error _buffer_allocate(Buffer *p_buffer, uint32_t p_size, D3D12_RESOURCE_STATES p_usage, D3D12_HEAP_TYPE p_heap_type);
-	Error _buffer_free(Buffer *p_buffer);
-	Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_list = false, uint32_t p_required_align = 32);
-
-	/*********************/
-	/**** FRAMEBUFFER ****/
-	/*********************/
-
-	static D3D12_RENDER_TARGET_VIEW_DESC _make_rtv_for_texture(const RenderingDeviceD3D12::Texture *p_texture, uint32_t p_mipmap_offset = 0, uint32_t p_layer_offset = 0, uint32_t p_layers = UINT32_MAX);
-	static D3D12_DEPTH_STENCIL_VIEW_DESC _make_dsv_for_texture(const RenderingDeviceD3D12::Texture *p_texture);
-
-	// In Vulkan we'd create some structures the driver uses for render pass based rendering.
-	// (Dynamic rendering is supported on Vulkan 1.3+, though, but Godot is not using it.)
-	// In contrast, in D3D12 we'll go the dynamic rendering way, since it's more convenient
-	// and render pass based render setup is not available on every version.
-	// Therefore, we just need to keep the data at hand and use it where appropriate.
-
-	struct FramebufferFormat {
-		Vector<AttachmentFormat> attachments;
-		Vector<FramebufferPass> passes;
-		Vector<TextureSamples> pass_samples;
-		uint32_t view_count = 1;
-		uint32_t max_supported_sample_count = 1;
-	};
-
-	bool _framebuffer_format_preprocess(FramebufferFormat *p_fb_format, uint32_t p_view_count);
-
-	HashMap<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
-
-	struct Framebuffer {
-		DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
-		FramebufferFormatID format_id = 0;
-		Vector<RID> texture_ids; // Empty if for screen.
-		InvalidationCallback invalidated_callback = nullptr;
-		void *invalidated_callback_userdata = nullptr;
-		Vector<uint32_t> attachments_handle_inds; // RTV heap index for color; DSV heap index for DSV.
-		Size2 size;
-		uint32_t view_count = 1;
-		DescriptorsHeap rtv_heap; // Used only if not for screen and some color attachments.
-		D3D12_CPU_DESCRIPTOR_HANDLE screen_rtv_handle = {}; // Used only if for screen.
-		DescriptorsHeap dsv_heap; // Used only if not for screen and some depth-stencil attachments.
-	};
-
-	RID_Owner<Framebuffer, true> framebuffer_owner;
-
-	/***********************/
-	/**** VERTEX BUFFER ****/
-	/***********************/
-
-	RID_Owner<Buffer, true> vertex_buffer_owner;
-
-	struct VertexDescriptionKey {
-		Vector<VertexAttribute> vertex_formats;
-		bool operator==(const VertexDescriptionKey &p_key) const {
-			int vdc = vertex_formats.size();
-			int vdck = p_key.vertex_formats.size();
-
-			if (vdc != vdck) {
-				return false;
-			} else {
-				const VertexAttribute *a_ptr = vertex_formats.ptr();
-				const VertexAttribute *b_ptr = p_key.vertex_formats.ptr();
-				for (int i = 0; i < vdc; i++) {
-					const VertexAttribute &a = a_ptr[i];
-					const VertexAttribute &b = b_ptr[i];
-
-					if (a.location != b.location) {
-						return false;
-					}
-					if (a.offset != b.offset) {
-						return false;
-					}
-					if (a.format != b.format) {
-						return false;
-					}
-					if (a.stride != b.stride) {
-						return false;
-					}
-					if (a.frequency != b.frequency) {
-						return false;
-					}
-				}
-				return true; // They are equal.
-			}
-		}
-
-		uint32_t hash() const {
-			int vdc = vertex_formats.size();
-			uint32_t h = hash_murmur3_one_32(vdc);
-			const VertexAttribute *ptr = vertex_formats.ptr();
-			for (int i = 0; i < vdc; i++) {
-				const VertexAttribute &vd = ptr[i];
-				h = hash_murmur3_one_32(vd.location, h);
-				h = hash_murmur3_one_32(vd.offset, h);
-				h = hash_murmur3_one_32(vd.format, h);
-				h = hash_murmur3_one_32(vd.stride, h);
-				h = hash_murmur3_one_32(vd.frequency, h);
-			}
-			return hash_fmix32(h);
-		}
-	};
-
-	struct VertexDescriptionHash {
-		static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) {
-			return p_key.hash();
-		}
-	};
-
-	// This is a cache and it's never freed, it ensures that
-	// ID used for a specific format always remain the same.
-	HashMap<VertexDescriptionKey, VertexFormatID, VertexDescriptionHash> vertex_format_cache;
-
-	struct VertexDescriptionCache {
-		Vector<VertexAttribute> vertex_formats;
-		Vector<D3D12_INPUT_ELEMENT_DESC> elements_desc;
-	};
-
-	HashMap<VertexFormatID, VertexDescriptionCache> vertex_formats;
-
-	struct VertexArray {
-		Vector<Buffer *> unique_buffers;
-		VertexFormatID description = 0;
-		int vertex_count = 0;
-		uint32_t max_instances_allowed = 0;
-		Vector<D3D12_VERTEX_BUFFER_VIEW> views;
-	};
-
-	RID_Owner<VertexArray, true> vertex_array_owner;
-
-	struct IndexBuffer : public Buffer {
-		uint32_t max_index = 0; // Used for validation.
-		uint32_t index_count = 0;
-		DXGI_FORMAT index_format = {};
-		bool supports_restart_indices = false;
-	};
-
-	RID_Owner<IndexBuffer, true> index_buffer_owner;
-
-	struct IndexArray {
-		IndexBuffer *buffer = nullptr;
-		uint32_t max_index = 0; // Remember the maximum index here too, for validation.
-		uint32_t offset = 0;
-		uint32_t indices = 0;
-		bool supports_restart_indices = false;
-		D3D12_INDEX_BUFFER_VIEW view = {};
-	};
-
-	RID_Owner<IndexArray, true> index_array_owner;
-
-	/****************/
-	/**** SHADER ****/
-	/****************/
-
-	static const uint32_t ROOT_SIGNATURE_SIZE = 256;
-	static const uint32_t PUSH_CONSTANT_SIZE = 128; // Mimicking Vulkan.
-
-	enum {
-		// We can only aim to set a maximum here, since depending on the shader
-		// there may be more or less root signature free for descriptor tables.
-		// Therefore, we'll have to rely on the final check at runtime, when building
-		// the root signature structure for a given shader.
-		// To be precise, these may be present or not, and their size vary statically:
-		// - Push constant (we'll assume this is always present to avoid reserving much
-		//   more space for descriptor sets than needed for almost any imaginable case,
-		//   given that most shader templates feature push constants).
-		// - NIR-DXIL runtime data.
-		MAX_UNIFORM_SETS = (ROOT_SIGNATURE_SIZE - PUSH_CONSTANT_SIZE) / sizeof(uint32_t),
-	};
-
-	enum ResourceClass {
-		RES_CLASS_INVALID,
-		RES_CLASS_CBV,
-		RES_CLASS_SRV,
-		RES_CLASS_UAV,
-	};
-
-	struct UniformBindingInfo {
-		uint32_t stages = 0; // Actual shader stages using the uniform (0 if totally optimized out).
-		ResourceClass res_class = RES_CLASS_INVALID;
-		struct RootSignatureLocation {
-			uint32_t root_param_idx = UINT32_MAX;
-			uint32_t range_idx = UINT32_MAX;
-		};
-		struct {
-			RootSignatureLocation resource;
-			RootSignatureLocation sampler;
-		} root_sig_locations;
-	};
-
-	struct UniformInfo {
-		UniformType type = UniformType::UNIFORM_TYPE_MAX;
-		bool writable = false;
-		int binding = 0;
-		int length = 0; // Size of arrays (in total elements), or ubos (in bytes * total elements).
-
-		bool operator!=(const UniformInfo &p_info) const {
-			return (binding != p_info.binding || type != p_info.type || writable != p_info.writable || length != p_info.length);
-		}
-
-		bool operator<(const UniformInfo &p_info) const {
-			if (binding != p_info.binding) {
-				return binding < p_info.binding;
-			}
-			if (type != p_info.type) {
-				return type < p_info.type;
-			}
-			if (writable != p_info.writable) {
-				return writable < p_info.writable;
-			}
-			return length < p_info.length;
-		}
-	};
-
-	struct UniformSetFormat {
-		Vector<UniformInfo> uniform_info;
-		bool operator<(const UniformSetFormat &p_format) const {
-			uint32_t size = uniform_info.size();
-			uint32_t psize = p_format.uniform_info.size();
-
-			if (size != psize) {
-				return size < psize;
-			}
-
-			const UniformInfo *infoptr = uniform_info.ptr();
-			const UniformInfo *pinfoptr = p_format.uniform_info.ptr();
-
-			for (uint32_t i = 0; i < size; i++) {
-				if (infoptr[i] != pinfoptr[i]) {
-					return infoptr[i] < pinfoptr[i];
-				}
-			}
-
-			return false;
-		}
-	};
-
-	// Always grows, never shrinks, ensuring unique IDs, but we assume
-	// the amount of formats will never be a problem, as the amount of shaders
-	// in a game is limited.
-	RBMap<UniformSetFormat, uint32_t> uniform_set_format_cache;
-	Vector<RBMap<UniformSetFormat, uint32_t>::Element *> uniform_set_format_cache_reverse;
-
-	struct Shader {
-		struct ShaderUniformInfo {
-			UniformInfo info;
-			UniformBindingInfo binding;
-
-			bool operator<(const ShaderUniformInfo &p_info) const {
-				return *((UniformInfo *)this) < (const UniformInfo &)p_info;
-			}
-		};
-		struct Set {
-			Vector<ShaderUniformInfo> uniforms;
-			struct {
-				uint32_t resources = 0;
-				uint32_t samplers = 0;
-			} num_root_params;
-		};
-
-		uint64_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
-		uint32_t fragment_output_mask = 0;
-
-		uint32_t spirv_push_constant_size = 0;
-		uint32_t dxil_push_constant_size = 0;
-		uint32_t nir_runtime_data_root_param_idx = UINT32_MAX;
-
-		uint32_t compute_local_size[3] = { 0, 0, 0 };
-
-		struct SpecializationConstant {
-			PipelineSpecializationConstant constant;
-			uint64_t stages_bit_offsets[D3D12_BITCODE_OFFSETS_NUM_STAGES];
-		};
-
-		bool is_compute = false;
-		Vector<Set> sets;
-		Vector<uint32_t> set_formats;
-		Vector<SpecializationConstant> specialization_constants;
-		uint32_t spirv_specialization_constants_ids_mask = 0;
-		HashMap<ShaderStage, Vector<uint8_t>> stages_bytecode;
-		String name; // Used for debug.
-
-		ComPtr<ID3D12RootSignature> root_signature;
-		ComPtr<ID3D12RootSignatureDeserializer> root_signature_deserializer;
-		const D3D12_ROOT_SIGNATURE_DESC *root_signature_desc = nullptr; // Owned by the deserializer.
-		uint32_t root_signature_crc = 0;
-	};
-
-	String _shader_uniform_debug(RID p_shader, int p_set = -1);
-
-	RID_Owner<Shader, true> shader_owner;
-
-	uint32_t _shader_patch_dxil_specialization_constant(
-			PipelineSpecializationConstantType p_type,
-			const void *p_value,
-			const uint64_t (&p_stages_bit_offsets)[D3D12_BITCODE_OFFSETS_NUM_STAGES],
-			HashMap<ShaderStage, Vector<uint8_t>> &r_stages_bytecodes,
-			bool p_is_first_patch);
-	bool _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob);
-
-	/******************/
-	/**** UNIFORMS ****/
-	/******************/
-
-	RID_Owner<Buffer, true> uniform_buffer_owner;
-	RID_Owner<Buffer, true> storage_buffer_owner;
-
-	// Texture buffer needs a view.
-	struct TextureBuffer {
-		Buffer buffer;
-	};
-
-	RID_Owner<TextureBuffer, true> texture_buffer_owner;
-
-	struct RootDescriptorTable {
-		uint32_t root_param_idx = UINT32_MAX;
-		D3D12_GPU_DESCRIPTOR_HANDLE start_gpu_handle = {};
-	};
-
-	// This structure contains the descriptor set. They _need_ to be allocated
-	// for a shader (and will be erased when this shader is erased), but should
-	// work for other shaders as long as the hash matches. This covers using
-	// them in shader variants.
-	//
-	// Keep also in mind that you can share buffers between descriptor sets, so
-	// the above restriction is not too serious.
-
-	struct UniformSet {
-		uint32_t format = 0;
-		RID shader_id;
-		uint32_t shader_set = 0;
-		struct {
-			DescriptorsHeap resources;
-			DescriptorsHeap samplers;
-		} desc_heaps;
-		struct StateRequirement {
-			Resource *resource;
-			bool is_buffer;
-			D3D12_RESOURCE_STATES states;
-			uint64_t shader_uniform_idx_mask;
-		};
-		struct AttachableTexture {
-			uint32_t bind;
-			RID texture;
-		};
-
-		struct RecentBind {
-			uint64_t execution_index = 0;
-			uint32_t root_signature_crc = 0;
-			struct {
-				LocalVector<RootDescriptorTable> resources;
-				LocalVector<RootDescriptorTable> samplers;
-			} root_tables;
-			int uses = 0;
-		} recent_binds[4]; // A better amount may be empirically found.
-
-		LocalVector<AttachableTexture> attachable_textures; // Used for validation.
-		Vector<StateRequirement> resource_states;
-		InvalidationCallback invalidated_callback = nullptr;
-		void *invalidated_callback_userdata = nullptr;
-
-#ifdef DEV_ENABLED
-		// Filthy, but useful for dev.
-		struct ResourceDescInfo {
-			D3D12_DESCRIPTOR_RANGE_TYPE type;
-			D3D12_SRV_DIMENSION srv_dimension;
-		};
-		LocalVector<ResourceDescInfo> _resources_desc_info;
-		const Shader *_shader = nullptr;
-#endif
-	};
-
-	RID_Owner<UniformSet, true> uniform_set_owner;
-
-	void _bind_uniform_set(UniformSet *p_uniform_set, const Shader::Set &p_shader_set, const Vector<UniformBindingInfo> &p_bindings, ID3D12GraphicsCommandList *p_command_list, bool p_for_compute);
-	void _apply_uniform_set_resource_states(const UniformSet *p_uniform_set, const Shader::Set &p_shader_set);
-
-	/*******************/
-	/**** PIPELINES ****/
-	/*******************/
-
-	Error _apply_specialization_constants(
-			const Shader *p_shader,
-			const Vector<PipelineSpecializationConstant> &p_specialization_constants,
-			HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode);
-#ifdef DEV_ENABLED
-	String _build_pipeline_blob_filename(
-			const Vector<uint8_t> &p_blob,
-			const Shader *p_shader,
-			const Vector<PipelineSpecializationConstant> &p_specialization_constants,
-			const String &p_extra_name_suffix = "",
-			const String &p_forced_id = "");
-	void _save_pso_blob(
-			ID3D12PipelineState *p_pso,
-			const Shader *p_shader,
-			const Vector<PipelineSpecializationConstant> &p_specialization_constants);
-	void _save_stages_bytecode(
-			const HashMap<ShaderStage, Vector<uint8_t>> &p_stages_bytecode,
-			const Shader *p_shader,
-			const RID p_shader_rid,
-			const Vector<PipelineSpecializationConstant> &p_specialization_constants);
-#endif
-
-	// Render pipeline contains ALL the
-	// information required for drawing.
-	// This includes all the rasterizer state
-	// as well as shader used, framebuffer format,
-	// etc.
-	// Some parameters aren't fixed in D3D12,
-	// so they are stored in an ancillary
-	// dynamic parameters structure to be set
-	// on pipeline activation via several calls.
-
-	struct RenderPipeline {
-		// Cached values for validation.
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			FramebufferFormatID framebuffer_format = 0;
-			uint32_t render_pass = 0;
-			uint32_t dynamic_state = 0;
-			VertexFormatID vertex_format = 0;
-			bool uses_restart_indices = false;
-			uint32_t primitive_minimum = 0;
-			uint32_t primitive_divisor = 0;
-		} validation;
-#endif
-		RID shader;
-		Vector<uint32_t> set_formats;
-		uint32_t bindings_id = 0;
-		ComPtr<ID3D12PipelineState> pso;
-		uint32_t root_signature_crc = 0;
-		uint32_t spirv_push_constant_size = 0;
-		uint32_t dxil_push_constant_size = 0;
-		uint32_t nir_runtime_data_root_param_idx = UINT32_MAX;
-		struct DynamicParams {
-			D3D12_PRIMITIVE_TOPOLOGY primitive_topology = {};
-			Color blend_constant;
-			float depth_bounds_min = 0.0f;
-			float depth_bounds_max = 0.0f;
-			uint32_t stencil_reference = 0;
-		} dyn_params;
-	};
-
-	HashMap<uint32_t, Vector<Vector<UniformBindingInfo>>> pipeline_bindings;
-	uint32_t next_pipeline_binding_id = 1;
-
-	RID_Owner<RenderPipeline, true> render_pipeline_owner;
-
-	struct ComputePipeline {
-		RID shader;
-		Vector<uint32_t> set_formats;
-		uint32_t bindings_id = 0;
-		ComPtr<ID3D12PipelineState> pso;
-		uint32_t root_signature_crc = 0;
-		uint32_t spirv_push_constant_size = 0;
-		uint32_t dxil_push_constant_size = 0;
-		uint32_t local_group_size[3] = { 0, 0, 0 };
-	};
-
-	RID_Owner<ComputePipeline, true> compute_pipeline_owner;
-
-	/*******************/
-	/**** DRAW LIST ****/
-	/*******************/
-
-	// Draw list contains both the command buffer
-	// used for drawing as well as a LOT of
-	// information used for validation. This
-	// validation is cheap so most of it can
-	// also run in release builds.
-
-	// When using split command lists, this is
-	// implemented internally using bundles.
-	// As they can be created in threads,
-	// each needs its own command allocator.
-
-	struct SplitDrawListAllocator {
-		// All pointers are owned, but not using ComPtr to avoid overhead in the vector.
-		ID3D12CommandAllocator *command_allocator = nullptr;
-		Vector<ID3D12GraphicsCommandList *> command_lists; // One for each frame.
-	};
-
-	Vector<SplitDrawListAllocator> split_draw_list_allocators;
-
-	struct DrawList {
-		ID3D12GraphicsCommandList *command_list = nullptr; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
-		Rect2i viewport;
-		bool viewport_set = false;
-
-		struct SetState {
-			uint32_t pipeline_expected_format = 0;
-			uint32_t uniform_set_format = 0;
-			RID uniform_set;
-			bool bound = false;
-#ifdef DEV_ENABLED
-			// Filthy, but useful for dev.
-			const Vector<UniformInfo> *_pipeline_expected_format = nullptr;
-			const UniformSet *_uniform_set = nullptr;
-#endif
-		};
-
-		struct State {
-			SetState sets[MAX_UNIFORM_SETS];
-			uint32_t set_count = 0;
-			RID pipeline;
-			ID3D12PipelineState *pso = nullptr;
-			ID3D12PipelineState *bound_pso = nullptr;
-			RID pipeline_shader;
-			uint32_t pipeline_dxil_push_constant_size = 0;
-			uint32_t pipeline_bindings_id = 0;
-			uint32_t root_signature_crc = 0;
-			RID vertex_array;
-			RID index_array;
-#ifdef DEV_ENABLED
-			// Filthy, but useful for dev.
-			Shader *_shader = nullptr;
-#endif
-		} state;
-
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			bool active = true; // Means command buffer was not closed, so you can keep adding things.
-			// Actual render pass values.
-			uint32_t dynamic_state = 0;
-			VertexFormatID vertex_format = INVALID_ID;
-			uint32_t vertex_array_size = 0;
-			uint32_t vertex_max_instances_allowed = 0xFFFFFFFF;
-			bool index_buffer_uses_restart_indices = false;
-			uint32_t index_array_size = 0;
-			uint32_t index_array_max_index = 0;
-			uint32_t index_array_offset = 0;
-			Vector<uint32_t> set_formats;
-			Vector<bool> set_bound;
-			Vector<RID> set_rids;
-			// Last pipeline set values.
-			bool pipeline_active = false;
-			uint32_t pipeline_dynamic_state = 0;
-			VertexFormatID pipeline_vertex_format = INVALID_ID;
-			RID pipeline_shader;
-			bool pipeline_uses_restart_indices = false;
-			uint32_t pipeline_primitive_divisor = 0;
-			uint32_t pipeline_primitive_minimum = 0;
-			uint32_t pipeline_spirv_push_constant_size = 0;
-			bool pipeline_push_constant_supplied = false;
-		} validation;
-#else
-		struct Validation {
-			uint32_t vertex_array_size = 0;
-			uint32_t index_array_size = 0;
-			uint32_t index_array_offset;
-		} validation;
-#endif
-	};
-
-	DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split.
-	uint32_t draw_list_subpass_count = 0;
-	uint32_t draw_list_count = 0;
-	Framebuffer curr_screen_framebuffer; // Only valid while a screen draw list is open.
-	Framebuffer *draw_list_framebuffer = nullptr;
-	FinalAction draw_list_final_color_action = FINAL_ACTION_DISCARD;
-	FinalAction draw_list_final_depth_action = FINAL_ACTION_DISCARD;
-	Vector2 draw_list_viewport_size = {};
-	uint32_t draw_list_current_subpass = 0;
-
-	bool draw_list_split = false;
-	Vector<RID> draw_list_bound_textures;
-	bool draw_list_unbind_color_textures = false;
-	bool draw_list_unbind_depth_textures = false;
-
-	struct {
-		RID texture_bound;
-		bool configured = false;
-	} vrs_state;
-	uint32_t vrs_state_execution_index = 0;
-
-	Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, Point2i viewport_offset, Point2i viewport_size, ID3D12GraphicsCommandList *command_list, const Vector<RID> &p_storage_textures);
-	_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
-	Buffer *_get_buffer_from_owner(RID p_buffer);
-	Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
-	void _draw_list_free(Rect2i *r_last_viewport = nullptr);
-	void _draw_list_subpass_begin();
-	void _draw_list_subpass_end();
-
-	/**********************/
-	/**** COMPUTE LIST ****/
-	/**********************/
-
-	struct ComputeList {
-		ID3D12GraphicsCommandList *command_list = nullptr; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
-
-		struct SetState {
-			uint32_t pipeline_expected_format = 0;
-			uint32_t uniform_set_format = 0;
-			RID uniform_set;
-			bool bound = false;
-#ifdef DEV_ENABLED
-			// Filthy, but useful for dev.
-			const Vector<UniformInfo> *_pipeline_expected_format = nullptr;
-			const UniformSet *_uniform_set = nullptr;
-#endif
-		};
-
-		struct State {
-			HashSet<Texture *> textures_to_sampled_layout;
-			SetState sets[MAX_UNIFORM_SETS];
-			uint32_t set_count = 0;
-			RID pipeline;
-			ID3D12PipelineState *pso = nullptr;
-			ID3D12PipelineState *bound_pso = nullptr;
-			RID pipeline_shader;
-			uint32_t pipeline_dxil_push_constant_size = 0;
-			uint32_t pipeline_bindings_id = 0;
-			uint32_t root_signature_crc = 0;
-			uint32_t local_group_size[3] = { 0, 0, 0 };
-			bool allow_draw_overlap;
-#ifdef DEV_ENABLED
-			// Filthy, but useful for dev.
-			Shader *_shader = nullptr;
-#endif
-		} state;
-
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			bool active = true; // Means command buffer was not closed, so you can keep adding things.
-			Vector<uint32_t> set_formats;
-			Vector<bool> set_bound;
-			Vector<RID> set_rids;
-			// Last pipeline set values.
-			bool pipeline_active = false;
-			RID pipeline_shader;
-			uint32_t pipeline_spirv_push_constant_size = 0;
-			bool pipeline_push_constant_supplied = false;
-		} validation;
-#endif
-	};
-
-	ComputeList *compute_list = nullptr;
-
-	/**************************/
-	/**** FRAME MANAGEMENT ****/
-	/**************************/
-
-	// This is the frame structure. There are normally
-	// 3 of these (used for triple buffering), or 2
-	// (double buffering). They are cycled constantly.
-	//
-	// It contains two command buffers, one that is
-	// used internally for setting up (creating stuff)
-	// and another used mostly for drawing.
-	//
-	// They also contains a list of things that need
-	// to be disposed of when deleted, which can't
-	// happen immediately due to the asynchronous
-	// nature of the GPU. They will get deleted
-	// when the frame is cycled.
-
-	struct Frame {
-		// List in usage order, from last to free to first to free.
-		List<Buffer> buffers_to_dispose_of;
-		List<Texture> textures_to_dispose_of;
-		List<Framebuffer> framebuffers_to_dispose_of;
-		List<Shader> shaders_to_dispose_of;
-		List<RenderPipeline> render_pipelines_to_dispose_of;
-		List<ComputePipeline> compute_pipelines_to_dispose_of;
-		struct {
-			DescriptorsHeap resources;
-			DescriptorsHeap samplers;
-			DescriptorsHeap aux;
-			DescriptorsHeap rtv;
-		} desc_heaps;
-		struct {
-			DescriptorsHeap::Walker resources;
-			DescriptorsHeap::Walker samplers;
-			DescriptorsHeap::Walker aux;
-			DescriptorsHeap::Walker rtv;
-		} desc_heap_walkers;
-		struct {
-			bool resources;
-			bool samplers;
-			bool aux;
-			bool rtv;
-		} desc_heaps_exhausted_reported;
-		CD3DX12_CPU_DESCRIPTOR_HANDLE null_rtv_handle = {}; // For [[MANUAL_SUBPASSES]].
-
-		ComPtr<ID3D12CommandAllocator> setup_command_allocator;
-		ComPtr<ID3D12CommandAllocator> draw_command_allocator;
-		ComPtr<ID3D12GraphicsCommandList> setup_command_list; // Used at the beginning of every frame for set-up.
-		ComPtr<ID3D12GraphicsCommandList> draw_command_list;
-
-		struct Timestamp {
-			String description;
-			uint64_t value = 0;
-		};
-
-		ComPtr<ID3D12QueryHeap> timestamp_heap;
-
-		TightLocalVector<String> timestamp_names;
-		TightLocalVector<uint64_t> timestamp_cpu_values;
-		uint32_t timestamp_count = 0;
-		TightLocalVector<String> timestamp_result_names;
-		TightLocalVector<uint64_t> timestamp_cpu_result_values;
-		Buffer timestamp_result_values_buffer;
-		TightLocalVector<uint64_t> timestamp_result_values;
-		uint32_t timestamp_result_count = 0;
-		uint64_t index = 0;
-		uint64_t execution_index = 0;
-#ifdef DEV_ENABLED
-		uint32_t uniform_set_reused = 0;
-#endif
-	};
-
-	uint32_t max_timestamp_query_elements = 0;
-
-	TightLocalVector<Frame> frames; // Frames available, for main device they are cycled (usually 3), for local devices only 1.
-	int frame = 0; // Current frame.
-	int frame_count = 0; // Total amount of frames.
-	uint64_t frames_drawn = 0;
-	uint32_t execution_index = 0; // Gets incremented on every call to ExecuteCommandLists (each frame and each flush).
-	RID local_device;
-	bool local_device_processing = false;
-
-	void _free_pending_resources(int p_frame);
-
-//#define USE_SMALL_ALLOCS_POOL // Disabled by now; seems not to be beneficial as it is in Vulkan.
-#ifdef USE_SMALL_ALLOCS_POOL
-	union AllocPoolKey {
-		struct {
-			D3D12_HEAP_TYPE heap_type;
-			D3D12_HEAP_FLAGS heap_flags;
-		};
-		uint64_t key;
-	};
-	HashMap<uint64_t, ComPtr<D3D12MA::Pool>> small_allocs_pools;
-	D3D12MA::Pool *_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags);
-#endif
-
-	ComPtr<ID3D12CommandSignature> indirect_dispatch_cmd_sig;
-	RID aux_resource; // Used for causing full barriers.
-
-	D3D12Context *context = nullptr;
-
-	uint64_t image_memory = 0;
-	uint64_t buffer_memory = 0;
-
-	void _free_internal(RID p_id);
-	void _flush(bool p_flush_current_frame);
-
-	bool screen_prepared = false;
-
-	template <class T>
-	void _free_rids(T &p_owner, const char *p_type);
-
-	void _finalize_command_bufers();
-	void _begin_frame();
-
-#ifdef DEV_ENABLED
-	HashMap<RID, String> resource_names;
-#endif
-
-	HashMap<DXGI_FORMAT, uint32_t> format_sample_counts_mask_cache;
-	uint32_t _find_max_common_supported_sample_count(const DXGI_FORMAT *p_formats, uint32_t p_num_formats);
-
-public:
-	virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
-	virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
-	virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
-
-	virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0);
-	virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
-
-	virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const;
-	virtual bool texture_is_shared(RID p_texture);
-	virtual bool texture_is_valid(RID p_texture);
-	virtual TextureFormat texture_get_format(RID p_texture);
-	virtual Size2i texture_size(RID p_texture);
-	virtual uint64_t texture_get_native_handle(RID p_texture);
-
-	virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	/*********************/
-	/**** FRAMEBUFFER ****/
-	/*********************/
-
-	virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
-	virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
-	virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
-	virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
-
-	virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
-	virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
-	virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
-	virtual bool framebuffer_is_valid(RID p_framebuffer) const;
-	virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata);
-
-	virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
-
-	/*****************/
-	/**** SAMPLER ****/
-	/*****************/
-
-	virtual RID sampler_create(const SamplerState &p_state);
-	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const;
-
-	/**********************/
-	/**** VERTEX ARRAY ****/
-	/**********************/
-
-	virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
-
-	// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
-	virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats);
-	virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets = Vector<uint64_t>());
-
-	virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false);
-
-	virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count);
-
-	/****************/
-	/**** SHADER ****/
-	/****************/
-
-	virtual String shader_get_binary_cache_key() const;
-	virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
-
-	virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder = RID());
-	virtual RID shader_create_placeholder();
-
-	virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader);
-
-	/*****************/
-	/**** UNIFORM ****/
-	/*****************/
-
-	virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
-	virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0);
-	virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>());
-
-	virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
-	virtual bool uniform_set_is_valid(RID p_uniform_set);
-	virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
-
-	virtual Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer.
-	virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0);
-
-	/*************************/
-	/**** RENDER PIPELINE ****/
-	/*************************/
-
-	virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
-	virtual bool render_pipeline_is_valid(RID p_pipeline);
-
-	/**************************/
-	/**** COMPUTE PIPELINE ****/
-	/**************************/
-
-	virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
-	virtual bool compute_pipeline_is_valid(RID p_pipeline);
-
-	/****************/
-	/**** SCREEN ****/
-	/****************/
-
-	virtual int screen_get_width(DisplayServer::WindowID p_screen = 0) const;
-	virtual int screen_get_height(DisplayServer::WindowID p_screen = 0) const;
-	virtual FramebufferFormatID screen_get_framebuffer_format() const;
-
-	/********************/
-	/**** DRAW LISTS ****/
-	/********************/
-
-	virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
-	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-
-	virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
-	virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
-	virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
-	virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array);
-	virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array);
-	virtual void draw_list_set_line_width(DrawListID p_list, float p_width);
-	virtual void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size);
-
-	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
-
-	virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
-	virtual void draw_list_disable_scissor(DrawListID p_list);
-
-	virtual uint32_t draw_list_get_current_pass();
-	virtual DrawListID draw_list_switch_to_next_pass();
-	virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
-
-	virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	/***********************/
-	/**** COMPUTE LISTS ****/
-	/***********************/
-
-	virtual ComputeListID compute_list_begin(bool p_allow_draw_overlap = false);
-	virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline);
-	virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index);
-	virtual void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size);
-	virtual void compute_list_add_barrier(ComputeListID p_list);
-
-	virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
-	virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads);
-	virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset);
-	virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
-	virtual void full_barrier();
-
-	/**************/
-	/**** FREE ****/
-	/**************/
-
-	virtual void free(RID p_id);
-
-	/****************/
-	/**** Timing ****/
-	/****************/
-
-	virtual void capture_timestamp(const String &p_name);
-	virtual uint32_t get_captured_timestamps_count() const;
-	virtual uint64_t get_captured_timestamps_frame() const;
-	virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const;
-	virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
-	virtual String get_captured_timestamp_name(uint32_t p_index) const;
-
-	/****************/
-	/**** Limits ****/
-	/****************/
-
-	virtual uint64_t limit_get(Limit p_limit) const;
-
-	virtual void prepare_screen_for_drawing();
-
-	void initialize(D3D12Context *p_context, bool p_local_device = false);
-	void finalize();
-
-	virtual void swap_buffers(); // For main device.
-
-	virtual void submit(); // For local device.
-	virtual void sync(); // For local device.
-
-	virtual uint32_t get_frame_delay() const;
-
-	virtual RenderingDevice *create_local_device();
-
-	virtual uint64_t get_memory_usage(MemoryType p_type) const;
-
-	virtual void set_resource_name(RID p_id, const String p_name);
-
-	virtual void draw_command_begin_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1));
-	virtual void draw_command_insert_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1));
-	virtual void draw_command_end_label();
-
-	virtual String get_device_vendor_name() const;
-	virtual String get_device_name() const;
-	virtual RenderingDevice::DeviceType get_device_type() const;
-	virtual String get_device_api_version() const;
-	virtual String get_device_pipeline_cache_uuid() const;
-
-	virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
-
-	virtual bool has_feature(const Features p_feature) const;
-
-	RenderingDeviceD3D12();
-	~RenderingDeviceD3D12();
-};
-
-#endif // RENDERING_DEVICE_D3D12_H

+ 5491 - 0
drivers/d3d12/rendering_device_driver_d3d12.cpp

@@ -0,0 +1,5491 @@
+/**************************************************************************/
+/*  rendering_device_driver_d3d12.cpp                                     */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_device_driver_d3d12.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/marshalls.h"
+#include "d3d12_context.h"
+#include "d3d12_godot_nir_bridge.h"
+#include "thirdparty/zlib/zlib.h"
+
+// No point in fighting warnings in Mesa.
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4200) // "nonstandard extension used: zero-sized array in struct/union".
+#pragma warning(disable : 4806) // "'&': unsafe operation: no value of type 'bool' promoted to type 'uint32_t' can equal the given constant".
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+#include "dxil_validator.h"
+#include "nir_spirv.h"
+#include "nir_to_dxil.h"
+#include "spirv_to_dxil.h"
+extern "C" {
+#include "dxil_spirv_nir.h"
+}
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if !defined(_MSC_VER)
+#include <guiddef.h>
+
+#include <dxguids.h>
+#endif
+
+// Mesa may define this.
+#ifdef UNUSED
+#undef UNUSED
+#endif
+
+static const D3D12_RANGE VOID_RANGE = {};
+
+static const uint32_t ROOT_CONSTANT_SPACE = RDD::MAX_UNIFORM_SETS + 1;
+static const uint32_t ROOT_CONSTANT_REGISTER = 0;
+static const uint32_t RUNTIME_DATA_SPACE = RDD::MAX_UNIFORM_SETS + 2;
+static const uint32_t RUNTIME_DATA_REGISTER = 0;
+
+#ifdef DEV_ENABLED
+//#define DEBUG_COUNT_BARRIERS
+#endif
+
+/*****************/
+/**** GENERIC ****/
+/*****************/
+
+// NOTE: RD's packed format names are reversed in relation to DXGI's; e.g.:.
+// - DATA_FORMAT_A8B8G8R8_UNORM_PACK32 -> DXGI_FORMAT_R8G8B8A8_UNORM (packed; note ABGR vs. RGBA).
+// - DATA_FORMAT_B8G8R8A8_UNORM -> DXGI_FORMAT_B8G8R8A8_UNORM (not packed; note BGRA order matches).
+// TODO: Add YUV formats properly, which would require better support for planes in the RD API.
+
+const RenderingDeviceDriverD3D12::D3D12Format RenderingDeviceDriverD3D12::RD_TO_D3D12_FORMAT[RDD::DATA_FORMAT_MAX] = {
+	/* DATA_FORMAT_R4G4_UNORM_PACK8 */ {},
+	/* DATA_FORMAT_R4G4B4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
+	/* DATA_FORMAT_B4G4R4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
+	/* DATA_FORMAT_R5G6B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM },
+	/* DATA_FORMAT_B5G6R5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
+	/* DATA_FORMAT_R5G5B5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
+	/* DATA_FORMAT_B5G5R5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
+	/* DATA_FORMAT_A1R5G5B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM },
+	/* DATA_FORMAT_R8_UNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM },
+	/* DATA_FORMAT_R8_SNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SNORM },
+	/* DATA_FORMAT_R8_USCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
+	/* DATA_FORMAT_R8_SSCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
+	/* DATA_FORMAT_R8_UINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
+	/* DATA_FORMAT_R8_SINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
+	/* DATA_FORMAT_R8_SRGB */ {},
+	/* DATA_FORMAT_R8G8_UNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM },
+	/* DATA_FORMAT_R8G8_SNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SNORM },
+	/* DATA_FORMAT_R8G8_USCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
+	/* DATA_FORMAT_R8G8_SSCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
+	/* DATA_FORMAT_R8G8_UINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
+	/* DATA_FORMAT_R8G8_SINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
+	/* DATA_FORMAT_R8G8_SRGB */ {},
+	/* DATA_FORMAT_R8G8B8_UNORM */ {},
+	/* DATA_FORMAT_R8G8B8_SNORM */ {},
+	/* DATA_FORMAT_R8G8B8_USCALED */ {},
+	/* DATA_FORMAT_R8G8B8_SSCALED */ {},
+	/* DATA_FORMAT_R8G8B8_UINT */ {},
+	/* DATA_FORMAT_R8G8B8_SINT */ {},
+	/* DATA_FORMAT_R8G8B8_SRGB */ {},
+	/* DATA_FORMAT_B8G8R8_UNORM */ {},
+	/* DATA_FORMAT_B8G8R8_SNORM */ {},
+	/* DATA_FORMAT_B8G8R8_USCALED */ {},
+	/* DATA_FORMAT_B8G8R8_SSCALED */ {},
+	/* DATA_FORMAT_B8G8R8_UINT */ {},
+	/* DATA_FORMAT_B8G8R8_SINT */ {},
+	/* DATA_FORMAT_B8G8R8_SRGB */ {},
+	/* DATA_FORMAT_R8G8B8A8_UNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
+	/* DATA_FORMAT_R8G8B8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
+	/* DATA_FORMAT_R8G8B8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_R8G8B8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_R8G8B8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_R8G8B8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_R8G8B8A8_SRGB */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
+	/* DATA_FORMAT_B8G8R8A8_UNORM */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM },
+	/* DATA_FORMAT_B8G8R8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
+	/* DATA_FORMAT_B8G8R8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_B8G8R8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_B8G8R8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_B8G8R8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_B8G8R8A8_SRGB */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
+	/* DATA_FORMAT_A8B8G8R8_UNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
+	/* DATA_FORMAT_A8B8G8R8_SNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
+	/* DATA_FORMAT_A8B8G8R8_USCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_A8B8G8R8_SSCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_A8B8G8R8_UINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
+	/* DATA_FORMAT_A8B8G8R8_SINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
+	/* DATA_FORMAT_A8B8G8R8_SRGB_PACK32 */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },
+	/* DATA_FORMAT_A2R10G10B10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
+	/* DATA_FORMAT_A2R10G10B10_SNORM_PACK32 */ {},
+	/* DATA_FORMAT_A2R10G10B10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
+	/* DATA_FORMAT_A2R10G10B10_SSCALED_PACK32 */ {},
+	/* DATA_FORMAT_A2R10G10B10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
+	/* DATA_FORMAT_A2R10G10B10_SINT_PACK32 */ {},
+	/* DATA_FORMAT_A2B10G10R10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM },
+	/* DATA_FORMAT_A2B10G10R10_SNORM_PACK32 */ {},
+	/* DATA_FORMAT_A2B10G10R10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
+	/* DATA_FORMAT_A2B10G10R10_SSCALED_PACK32 */ {},
+	/* DATA_FORMAT_A2B10G10R10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
+	/* DATA_FORMAT_A2B10G10R10_SINT_PACK32 */ {},
+	/* DATA_FORMAT_R16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM },
+	/* DATA_FORMAT_R16_SNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SNORM },
+	/* DATA_FORMAT_R16_USCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
+	/* DATA_FORMAT_R16_SSCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
+	/* DATA_FORMAT_R16_UINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
+	/* DATA_FORMAT_R16_SINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
+	/* DATA_FORMAT_R16_SFLOAT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_FLOAT },
+	/* DATA_FORMAT_R16G16_UNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM },
+	/* DATA_FORMAT_R16G16_SNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SNORM },
+	/* DATA_FORMAT_R16G16_USCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
+	/* DATA_FORMAT_R16G16_SSCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
+	/* DATA_FORMAT_R16G16_UINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
+	/* DATA_FORMAT_R16G16_SINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
+	/* DATA_FORMAT_R16G16_SFLOAT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_FLOAT },
+	/* DATA_FORMAT_R16G16B16_UNORM */ {},
+	/* DATA_FORMAT_R16G16B16_SNORM */ {},
+	/* DATA_FORMAT_R16G16B16_USCALED */ {},
+	/* DATA_FORMAT_R16G16B16_SSCALED */ {},
+	/* DATA_FORMAT_R16G16B16_UINT */ {},
+	/* DATA_FORMAT_R16G16B16_SINT */ {},
+	/* DATA_FORMAT_R16G16B16_SFLOAT */ {},
+	/* DATA_FORMAT_R16G16B16A16_UNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM },
+	/* DATA_FORMAT_R16G16B16A16_SNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SNORM },
+	/* DATA_FORMAT_R16G16B16A16_USCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
+	/* DATA_FORMAT_R16G16B16A16_SSCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
+	/* DATA_FORMAT_R16G16B16A16_UINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
+	/* DATA_FORMAT_R16G16B16A16_SINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
+	/* DATA_FORMAT_R16G16B16A16_SFLOAT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_FLOAT },
+	/* DATA_FORMAT_R32_UINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT },
+	/* DATA_FORMAT_R32_SINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_SINT },
+	/* DATA_FORMAT_R32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT },
+	/* DATA_FORMAT_R32G32_UINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_UINT },
+	/* DATA_FORMAT_R32G32_SINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_SINT },
+	/* DATA_FORMAT_R32G32_SFLOAT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_FLOAT },
+	/* DATA_FORMAT_R32G32B32_UINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_UINT },
+	/* DATA_FORMAT_R32G32B32_SINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_SINT },
+	/* DATA_FORMAT_R32G32B32_SFLOAT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT },
+	/* DATA_FORMAT_R32G32B32A32_UINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_UINT },
+	/* DATA_FORMAT_R32G32B32A32_SINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_SINT },
+	/* DATA_FORMAT_R32G32B32A32_SFLOAT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT },
+	/* DATA_FORMAT_R64_UINT */ {},
+	/* DATA_FORMAT_R64_SINT */ {},
+	/* DATA_FORMAT_R64_SFLOAT */ {},
+	/* DATA_FORMAT_R64G64_UINT */ {},
+	/* DATA_FORMAT_R64G64_SINT */ {},
+	/* DATA_FORMAT_R64G64_SFLOAT */ {},
+	/* DATA_FORMAT_R64G64B64_UINT */ {},
+	/* DATA_FORMAT_R64G64B64_SINT */ {},
+	/* DATA_FORMAT_R64G64B64_SFLOAT */ {},
+	/* DATA_FORMAT_R64G64B64A64_UINT */ {},
+	/* DATA_FORMAT_R64G64B64A64_SINT */ {},
+	/* DATA_FORMAT_R64G64B64A64_SFLOAT */ {},
+	/* DATA_FORMAT_B10G11R11_UFLOAT_PACK32 */ { DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT },
+	/* DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32 */ { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
+	/* DATA_FORMAT_D16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, 0, DXGI_FORMAT_D16_UNORM },
+	/* DATA_FORMAT_X8_D24_UNORM_PACK32 */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
+	/* DATA_FORMAT_D32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT },
+	/* DATA_FORMAT_S8_UINT */ {},
+	/* DATA_FORMAT_D16_UNORM_S8_UINT */ {},
+	/* DATA_FORMAT_D24_UNORM_S8_UINT */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
+	/* DATA_FORMAT_D32_SFLOAT_S8_UINT */ { DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT_S8X24_UINT },
+	/* DATA_FORMAT_BC1_RGB_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
+	/* DATA_FORMAT_BC1_RGB_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
+	/* DATA_FORMAT_BC1_RGBA_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM },
+	/* DATA_FORMAT_BC1_RGBA_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB },
+	/* DATA_FORMAT_BC2_UNORM_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM },
+	/* DATA_FORMAT_BC2_SRGB_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM_SRGB },
+	/* DATA_FORMAT_BC3_UNORM_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM },
+	/* DATA_FORMAT_BC3_SRGB_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM_SRGB },
+	/* DATA_FORMAT_BC4_UNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM },
+	/* DATA_FORMAT_BC4_SNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_SNORM },
+	/* DATA_FORMAT_BC5_UNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM },
+	/* DATA_FORMAT_BC5_SNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_SNORM },
+	/* DATA_FORMAT_BC6H_UFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16 },
+	/* DATA_FORMAT_BC6H_SFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_SF16 },
+	/* DATA_FORMAT_BC7_UNORM_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM },
+	/* DATA_FORMAT_BC7_SRGB_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM_SRGB },
+	/* DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_EAC_R11_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_EAC_R11_SNORM_BLOCK */ {},
+	/* DATA_FORMAT_EAC_R11G11_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_EAC_R11G11_SNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_4x4_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_4x4_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_5x4_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_5x4_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_5x5_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_5x5_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_6x5_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_6x5_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_6x6_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_6x6_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x5_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x5_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x6_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x6_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x8_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_8x8_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x5_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x5_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x6_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x6_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x8_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x8_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x10_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_10x10_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_12x10_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_12x10_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_12x12_UNORM_BLOCK */ {},
+	/* DATA_FORMAT_ASTC_12x12_SRGB_BLOCK */ {},
+	/* DATA_FORMAT_G8B8G8R8_422_UNORM */ {},
+	/* DATA_FORMAT_B8G8R8G8_422_UNORM */ {},
+	/* DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM */ {},
+	/* DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM */ {},
+	/* DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM */ {},
+	/* DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM */ {},
+	/* DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM */ {},
+	/* DATA_FORMAT_R10X6_UNORM_PACK16 */ {},
+	/* DATA_FORMAT_R10X6G10X6_UNORM_2PACK16 */ {},
+	/* DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_R12X4_UNORM_PACK16 */ {},
+	/* DATA_FORMAT_R12X4G12X4_UNORM_2PACK16 */ {},
+	/* DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 */ {},
+	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 */ {},
+	/* DATA_FORMAT_G16B16G16R16_422_UNORM */ {},
+	/* DATA_FORMAT_B16G16R16G16_422_UNORM */ {},
+	/* DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM */ {},
+	/* DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM */ {},
+	/* DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM */ {},
+	/* DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM */ {},
+	/* DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM */ {},
+};
+
+Error RenderingDeviceDriverD3D12::DescriptorsHeap::allocate(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type, uint32_t p_descriptor_count, bool p_for_gpu) {
+	ERR_FAIL_COND_V(heap, ERR_ALREADY_EXISTS);
+	ERR_FAIL_COND_V(p_descriptor_count == 0, ERR_INVALID_PARAMETER);
+
+	handle_size = p_device->GetDescriptorHandleIncrementSize(p_type);
+
+	desc.Type = p_type;
+	desc.NumDescriptors = p_descriptor_count;
+	desc.Flags = p_for_gpu ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
+	HRESULT res = p_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(heap.GetAddressOf()));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CreateDescriptorHeap failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	return OK;
+}
+
+RenderingDeviceDriverD3D12::DescriptorsHeap::Walker RenderingDeviceDriverD3D12::DescriptorsHeap::make_walker() const {
+	Walker walker;
+	walker.handle_size = handle_size;
+	walker.handle_count = desc.NumDescriptors;
+	if (heap) {
+#if defined(_MSC_VER) || !defined(_WIN32)
+		walker.first_cpu_handle = heap->GetCPUDescriptorHandleForHeapStart();
+		if ((desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
+			walker.first_gpu_handle = heap->GetGPUDescriptorHandleForHeapStart();
+		}
+#else
+		heap->GetCPUDescriptorHandleForHeapStart(&walker.first_cpu_handle);
+		if ((desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
+			heap->GetGPUDescriptorHandleForHeapStart(&walker.first_gpu_handle);
+		}
+#endif
+	}
+	return walker;
+}
+
+void RenderingDeviceDriverD3D12::DescriptorsHeap::Walker::advance(uint32_t p_count) {
+	ERR_FAIL_COND_MSG(handle_index + p_count > handle_count, "Would advance past EOF.");
+	handle_index += p_count;
+}
+
+D3D12_CPU_DESCRIPTOR_HANDLE RenderingDeviceDriverD3D12::DescriptorsHeap::Walker::get_curr_cpu_handle() {
+	ERR_FAIL_COND_V_MSG(is_at_eof(), D3D12_CPU_DESCRIPTOR_HANDLE(), "Heap walker is at EOF.");
+	return D3D12_CPU_DESCRIPTOR_HANDLE{ first_cpu_handle.ptr + handle_index * handle_size };
+}
+
+D3D12_GPU_DESCRIPTOR_HANDLE RenderingDeviceDriverD3D12::DescriptorsHeap::Walker::get_curr_gpu_handle() {
+	ERR_FAIL_COND_V_MSG(!first_gpu_handle.ptr, D3D12_GPU_DESCRIPTOR_HANDLE(), "Can't provide a GPU handle from a non-GPU descriptors heap.");
+	ERR_FAIL_COND_V_MSG(is_at_eof(), D3D12_GPU_DESCRIPTOR_HANDLE(), "Heap walker is at EOF.");
+	return D3D12_GPU_DESCRIPTOR_HANDLE{ first_gpu_handle.ptr + handle_index * handle_size };
+}
+
+static const D3D12_COMPARISON_FUNC RD_TO_D3D12_COMPARE_OP[RD::COMPARE_OP_MAX] = {
+	D3D12_COMPARISON_FUNC_NEVER,
+	D3D12_COMPARISON_FUNC_LESS,
+	D3D12_COMPARISON_FUNC_EQUAL,
+	D3D12_COMPARISON_FUNC_LESS_EQUAL,
+	D3D12_COMPARISON_FUNC_GREATER,
+	D3D12_COMPARISON_FUNC_NOT_EQUAL,
+	D3D12_COMPARISON_FUNC_GREATER_EQUAL,
+	D3D12_COMPARISON_FUNC_ALWAYS,
+};
+
+/****************/
+/**** MEMORY ****/
+/****************/
+
+static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
+
+#ifdef USE_SMALL_ALLOCS_POOL
+D3D12MA::Pool *RenderingDeviceDriverD3D12::_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags) {
+	D3D12_HEAP_FLAGS effective_heap_flags = p_heap_flags;
+	if (allocator->GetD3D12Options().ResourceHeapTier != D3D12_RESOURCE_HEAP_TIER_1) {
+		// Heap tier 2 allows mixing resource types liberally.
+		effective_heap_flags &= ~(D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS | D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES);
+	}
+
+	AllocPoolKey pool_key;
+	pool_key.heap_type = p_heap_type;
+	pool_key.heap_flags = effective_heap_flags;
+	if (small_allocs_pools.has(pool_key.key)) {
+		return small_allocs_pools[pool_key.key].Get();
+	}
+
+#ifdef DEV_ENABLED
+	print_verbose("Creating D3D12MA small objects pool for heap type " + itos(p_heap_type) + " and heap flags " + itos(p_heap_flags));
+#endif
+
+	D3D12MA::POOL_DESC poolDesc = {};
+	poolDesc.HeapProperties.Type = p_heap_type;
+	poolDesc.HeapFlags = effective_heap_flags;
+
+	ComPtr<D3D12MA::Pool> pool;
+	HRESULT res = allocator->CreatePool(&poolDesc, pool.GetAddressOf());
+	small_allocs_pools[pool_key.key] = pool; // Don't try to create it again if failed the first time.
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "CreatePool failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	return pool.Get();
+}
+#endif
+
+/******************/
+/**** RESOURCE ****/
+/******************/
+
+static const D3D12_RESOURCE_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[RD::TEXTURE_TYPE_MAX] = {
+	D3D12_RESOURCE_DIMENSION_TEXTURE1D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE3D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE1D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+	D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+};
+
+void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override) {
+	DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here.
+	DEV_ASSERT(p_new_state != D3D12_RESOURCE_STATE_COMMON); // No need to support this for now.
+
+#ifdef DEBUG_COUNT_BARRIERS
+	uint64_t start = OS::get_singleton()->get_ticks_usec();
+#endif
+
+	ResourceInfo::States *res_states = p_resource->states_ptr;
+	D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource];
+
+	ID3D12Resource *res_to_transition = p_resource_override ? p_resource_override : p_resource->resource;
+
+	bool redundant_transition = ((*curr_state) & p_new_state) == p_new_state;
+	if (redundant_transition) {
+		bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+		bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
+		if (needs_uav_barrier) {
+			if (res_barriers.size() < res_barriers_count + 1) {
+				res_barriers.resize(res_barriers_count + 1);
+			}
+			res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(res_to_transition);
+			res_barriers_count++;
+			res_states->last_batch_with_uav_barrier = res_barriers_batch;
+		}
+	} else {
+		uint64_t subres_mask_piece = ((uint64_t)1 << (p_subresource & 0b111111));
+		uint8_t subres_qword = p_subresource >> 6;
+
+		if (res_barriers_requests.has(res_states)) {
+			BarrierRequest &br = res_barriers_requests.get(res_states);
+			DEV_ASSERT(br.dx_resource == res_to_transition);
+			DEV_ASSERT(br.subres_mask_qwords == STEPIFY(res_states->subresource_states.size(), 64) / 64);
+			DEV_ASSERT(br.planes == p_num_planes);
+
+			// First, find if the subresource already has a barrier scheduled.
+			uint8_t curr_group_idx = 0;
+			bool same_transition_scheduled = false;
+			for (curr_group_idx = 0; curr_group_idx < br.groups_count; curr_group_idx++) {
+				if (unlikely(br.groups[curr_group_idx].states == BarrierRequest::DELETED_GROUP)) {
+					continue;
+				}
+				if ((br.groups[curr_group_idx].subres_mask[subres_qword] & subres_mask_piece)) {
+					uint32_t state_mask = br.groups[curr_group_idx].states;
+					same_transition_scheduled = (state_mask & (uint32_t)p_new_state) == (uint32_t)p_new_state;
+					break;
+				}
+			}
+			if (!same_transition_scheduled) {
+				bool subres_already_there = curr_group_idx != br.groups_count;
+				D3D12_RESOURCE_STATES final_states = {};
+				if (subres_already_there) {
+					final_states = br.groups[curr_group_idx].states;
+					final_states |= p_new_state;
+					bool subres_alone = true;
+					for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
+						if (i == subres_qword) {
+							if (br.groups[curr_group_idx].subres_mask[i] != subres_mask_piece) {
+								subres_alone = false;
+								break;
+							}
+						} else {
+							if (br.groups[curr_group_idx].subres_mask[i] != 0) {
+								subres_alone = false;
+								break;
+							}
+						}
+					}
+					bool relocated = false;
+					if (subres_alone) {
+						// Subresource is there by itself.
+						for (uint8_t i = 0; i < br.groups_count; i++) {
+							if (unlikely(i == curr_group_idx)) {
+								continue;
+							}
+							if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {
+								continue;
+							}
+							// There's another group with the final states; relocate to it.
+							if (br.groups[i].states == final_states) {
+								br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
+								relocated = true;
+								break;
+							}
+						}
+						if (relocated) {
+							// Let's delete the group where it used to be by itself.
+							if (curr_group_idx == br.groups_count - 1) {
+								br.groups_count--;
+							} else {
+								br.groups[curr_group_idx].states = BarrierRequest::DELETED_GROUP;
+							}
+						} else {
+							// Its current group, where it's alone, can extend its states.
+							br.groups[curr_group_idx].states = final_states;
+						}
+					} else {
+						// Already there, but not by itself and the state mask is different, so it now belongs to a different group.
+						br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
+						subres_already_there = false;
+					}
+				} else {
+					final_states = p_new_state;
+				}
+				if (!subres_already_there) {
+					// See if it fits exactly the states of some of the groups to fit it there.
+					for (uint8_t i = 0; i < br.groups_count; i++) {
+						if (unlikely(i == curr_group_idx)) {
+							continue;
+						}
+						if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {
+							continue;
+						}
+						if (br.groups[i].states == final_states) {
+							br.groups[i].subres_mask[subres_qword] |= subres_mask_piece;
+							subres_already_there = true;
+							break;
+						}
+					}
+					if (!subres_already_there) {
+						// Add a new group to accommodate this subresource.
+						uint8_t group_to_fill = 0;
+						if (br.groups_count < BarrierRequest::MAX_GROUPS) {
+							// There are still free groups.
+							group_to_fill = br.groups_count;
+							br.groups_count++;
+						} else {
+							// Let's try to take over a deleted one.
+							for (; group_to_fill < br.groups_count; group_to_fill++) {
+								if (unlikely(br.groups[group_to_fill].states == BarrierRequest::DELETED_GROUP)) {
+									break;
+								}
+							}
+							CRASH_COND(group_to_fill == br.groups_count);
+						}
+
+						br.groups[group_to_fill].states = final_states;
+						for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
+							if (unlikely(i == subres_qword)) {
+								br.groups[group_to_fill].subres_mask[i] = subres_mask_piece;
+							} else {
+								br.groups[group_to_fill].subres_mask[i] = 0;
+							}
+						}
+					}
+				}
+			}
+		} else {
+			BarrierRequest &br = res_barriers_requests[res_states];
+			br.dx_resource = res_to_transition;
+			br.subres_mask_qwords = STEPIFY(p_resource->states_ptr->subresource_states.size(), 64) / 64;
+			CRASH_COND(p_resource->states_ptr->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES);
+			br.planes = p_num_planes;
+			br.groups[0].states = p_new_state;
+			for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
+				if (unlikely(i == subres_qword)) {
+					br.groups[0].subres_mask[i] = subres_mask_piece;
+				} else {
+					br.groups[0].subres_mask[i] = 0;
+				}
+			}
+			br.groups_count = 1;
+		}
+	}
+
+	if (p_new_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
+		res_states->last_batch_transitioned_to_uav = res_barriers_batch;
+	}
+
+#ifdef DEBUG_COUNT_BARRIERS
+	frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
+#endif
+}
+
+void RenderingDeviceDriverD3D12::_resource_transitions_flush(ID3D12GraphicsCommandList *p_cmd_list) {
+#ifdef DEBUG_COUNT_BARRIERS
+	uint64_t start = OS::get_singleton()->get_ticks_usec();
+#endif
+
+	for (const KeyValue<ResourceInfo::States *, BarrierRequest> &E : res_barriers_requests) {
+		ResourceInfo::States *res_states = E.key;
+		const BarrierRequest &br = E.value;
+
+		uint32_t num_subresources = res_states->subresource_states.size();
+
+		// When there's not a lot of subresources, the empirical finding is that it's better
+		// to avoid attempting the single-barrier optimization.
+		static const uint32_t SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES = 48;
+
+		bool may_do_single_barrier = br.groups_count == 1 && num_subresources * br.planes >= SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES;
+		if (may_do_single_barrier) {
+			// A single group means we may be able to do a single all-subresources barrier.
+
+			{
+				// First requisite is that all subresources are involved.
+
+				uint8_t subres_mask_full_qwords = num_subresources / 64;
+				for (uint32_t i = 0; i < subres_mask_full_qwords; i++) {
+					if (br.groups[0].subres_mask[i] != UINT64_MAX) {
+						may_do_single_barrier = false;
+						break;
+					}
+				}
+				if (may_do_single_barrier) {
+					if (num_subresources % 64) {
+						DEV_ASSERT(br.subres_mask_qwords == subres_mask_full_qwords + 1);
+						uint64_t mask_tail_qword = 0;
+						for (uint8_t i = 0; i < num_subresources % 64; i++) {
+							mask_tail_qword |= ((uint64_t)1 << i);
+						}
+						if ((br.groups[0].subres_mask[subres_mask_full_qwords] & mask_tail_qword) != mask_tail_qword) {
+							may_do_single_barrier = false;
+						}
+					}
+				}
+			}
+
+			if (may_do_single_barrier) {
+				// Second requisite is that the source state is the same for all.
+
+				for (uint32_t i = 1; i < num_subresources; i++) {
+					if (res_states->subresource_states[i] != res_states->subresource_states[0]) {
+						may_do_single_barrier = false;
+						break;
+					}
+				}
+
+				if (may_do_single_barrier) {
+					// Hurray!, we can do a single barrier (plus maybe a UAV one, too).
+
+					bool just_written = res_states->subresource_states[0] == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
+
+					uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + 1;
+					if (res_barriers.size() < res_barriers_count + needed_barriers) {
+						res_barriers.resize(res_barriers_count + needed_barriers);
+					}
+
+					if (needs_uav_barrier) {
+						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
+						res_barriers_count++;
+						res_states->last_batch_with_uav_barrier = res_barriers_batch;
+					}
+
+					if (res_states->subresource_states[0] != br.groups[0].states) {
+						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].states, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
+						res_barriers_count++;
+					}
+
+					for (uint32_t i = 0; i < num_subresources; i++) {
+						res_states->subresource_states[i] = br.groups[0].states;
+					}
+				}
+			}
+		}
+
+		if (!may_do_single_barrier) {
+			for (uint8_t i = 0; i < br.groups_count; i++) {
+				const BarrierRequest::Group &g = E.value.groups[i];
+
+				if (unlikely(g.states == BarrierRequest::DELETED_GROUP)) {
+					continue;
+				}
+
+				uint32_t subresource = 0;
+				do {
+					uint64_t subres_mask_piece = ((uint64_t)1 << (subresource % 64));
+					uint8_t subres_qword = subresource / 64;
+
+					if (likely(g.subres_mask[subres_qword] == 0)) {
+						subresource += 64;
+						continue;
+					}
+
+					if (likely(!(g.subres_mask[subres_qword] & subres_mask_piece))) {
+						subresource++;
+						continue;
+					}
+
+					D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[subresource];
+
+					bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
+
+					uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + br.planes;
+					if (res_barriers.size() < res_barriers_count + needed_barriers) {
+						res_barriers.resize(res_barriers_count + needed_barriers);
+					}
+
+					if (needs_uav_barrier) {
+						res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
+						res_barriers_count++;
+						res_states->last_batch_with_uav_barrier = res_barriers_batch;
+					}
+
+					if (*curr_state != g.states) {
+						for (uint8_t k = 0; k < br.planes; k++) {
+							res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.states, subresource + k * num_subresources);
+							res_barriers_count++;
+						}
+					}
+
+					*curr_state = g.states;
+
+					subresource++;
+				} while (subresource < num_subresources);
+			}
+		}
+	}
+
+	if (res_barriers_count) {
+		p_cmd_list->ResourceBarrier(res_barriers_count, res_barriers.ptr());
+		res_barriers_requests.clear();
+	}
+
+#ifdef DEBUG_COUNT_BARRIERS
+	frame_barriers_count += res_barriers_count;
+	frame_barriers_batches_count++;
+	frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
+#endif
+
+	res_barriers_count = 0;
+	res_barriers_batch++;
+}
+
+/*****************/
+/**** BUFFERS ****/
+/*****************/
+
+RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) {
+	// D3D12 debug layers complain at CBV creation time if the size is not multiple of the value per the spec
+	// but also if you give a rounded size at that point because it will extend beyond the
+	// memory of the resource. Therefore, it seems the only way is to create it with a
+	// rounded size.
+	CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(STEPIFY(p_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT));
+	if (p_usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)) {
+		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+	} else {
+		resource_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+	}
+
+	D3D12MA::ALLOCATION_DESC allocation_desc = {};
+	allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
+	D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COPY_DEST;
+	switch (p_allocation_type) {
+		case MEMORY_ALLOCATION_TYPE_CPU: {
+			bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT);
+			bool is_dst = p_usage.has_flag(BUFFER_USAGE_TRANSFER_TO_BIT);
+			if (is_src && !is_dst) {
+				// Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM.
+				allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
+				initial_state = D3D12_RESOURCE_STATE_GENERIC_READ;
+			}
+			if (is_dst && !is_src) {
+				// Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads.
+				allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;
+			}
+		} break;
+		case MEMORY_ALLOCATION_TYPE_GPU: {
+#ifdef USE_SMALL_ALLOCS_POOL
+			if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
+				allocation_desc.CustomPool = _find_or_create_small_allocs_pool(allocation_desc.HeapType, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS);
+			}
+#endif
+		} break;
+	}
+
+	ComPtr<ID3D12Resource> buffer;
+	ComPtr<D3D12MA::Allocation> allocation;
+	HRESULT res = allocator->CreateResource(
+			&allocation_desc,
+			&resource_desc,
+			initial_state,
+			nullptr,
+			allocation.GetAddressOf(),
+			IID_PPV_ARGS(buffer.GetAddressOf()));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	// Bookkeep.
+
+	BufferInfo *buf_info = VersatileResource::allocate<BufferInfo>(resources_allocator);
+	buf_info->resource = buffer.Get();
+	buf_info->owner_info.resource = buffer;
+	buf_info->owner_info.allocation = allocation;
+	buf_info->owner_info.states.subresource_states.push_back(initial_state);
+	buf_info->states_ptr = &buf_info->owner_info.states;
+	buf_info->size = p_size;
+	buf_info->flags.usable_as_uav = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
+	buf_info->flags.is_for_upload = allocation_desc.HeapType == D3D12_HEAP_TYPE_UPLOAD;
+
+	return BufferID(buf_info);
+}
+
+bool RenderingDeviceDriverD3D12::buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) {
+	BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
+	buf_info->texel_format = p_format;
+	return true;
+}
+
+void RenderingDeviceDriverD3D12::buffer_free(BufferID p_buffer) {
+	BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
+	VersatileResource::free(resources_allocator, buf_info);
+}
+
+uint64_t RenderingDeviceDriverD3D12::buffer_get_allocation_size(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	return buf_info->owner_info.allocation ? buf_info->owner_info.allocation->GetSize() : 0;
+}
+
+uint8_t *RenderingDeviceDriverD3D12::buffer_map(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	void *data_ptr = nullptr;
+	HRESULT res = buf_info->resource->Map(0, &VOID_RANGE, &data_ptr);
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	return (uint8_t *)data_ptr;
+}
+
+void RenderingDeviceDriverD3D12::buffer_unmap(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	buf_info->resource->Unmap(0, &VOID_RANGE);
+}
+
+/*****************/
+/**** TEXTURE ****/
+/*****************/
+
+static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[RD::TEXTURE_TYPE_MAX] = {
+	D3D12_SRV_DIMENSION_TEXTURE1D,
+	D3D12_SRV_DIMENSION_TEXTURE2D,
+	D3D12_SRV_DIMENSION_TEXTURE3D,
+	D3D12_SRV_DIMENSION_TEXTURECUBE,
+	D3D12_SRV_DIMENSION_TEXTURE1DARRAY,
+	D3D12_SRV_DIMENSION_TEXTURE2DARRAY,
+	D3D12_SRV_DIMENSION_TEXTURECUBEARRAY,
+};
+
+static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[RD::TEXTURE_TYPE_MAX] = {
+	D3D12_SRV_DIMENSION_UNKNOWN,
+	D3D12_SRV_DIMENSION_TEXTURE2DMS,
+	D3D12_SRV_DIMENSION_UNKNOWN,
+	D3D12_SRV_DIMENSION_UNKNOWN,
+	D3D12_SRV_DIMENSION_UNKNOWN,
+	D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY,
+	D3D12_SRV_DIMENSION_UNKNOWN,
+};
+
+static const D3D12_UAV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[RD::TEXTURE_TYPE_MAX] = {
+	D3D12_UAV_DIMENSION_TEXTURE1D,
+	D3D12_UAV_DIMENSION_TEXTURE2D,
+	D3D12_UAV_DIMENSION_TEXTURE3D,
+	D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
+	D3D12_UAV_DIMENSION_TEXTURE1DARRAY,
+	D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
+	D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
+};
+
+uint32_t RenderingDeviceDriverD3D12::_find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats) {
+	uint32_t common = UINT32_MAX;
+
+	for (uint32_t i = 0; i < p_formats.size(); i++) {
+		if (format_sample_counts_mask_cache.has(p_formats[i])) {
+			common &= format_sample_counts_mask_cache[p_formats[i]];
+		} else {
+			D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msql = {};
+			msql.Format = p_formats[i];
+			uint32_t mask = 0;
+			for (int samples = 1 << (TEXTURE_SAMPLES_MAX - 1); samples >= 1; samples /= 2) {
+				msql.SampleCount = (UINT)samples;
+				HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msql, sizeof(msql));
+				if (SUCCEEDED(res) && msql.NumQualityLevels) {
+					int bit = get_shift_from_power_of_2(samples);
+					ERR_FAIL_COND_V(bit == -1, 1);
+					mask |= (uint32_t)(1 << bit);
+				}
+			}
+			format_sample_counts_mask_cache.insert(p_formats[i], mask);
+			common &= mask;
+		}
+	}
+	if (common == UINT32_MAX) {
+		return 1;
+	} else {
+		return ((uint32_t)1 << nearest_shift(common));
+	}
+}
+
+UINT RenderingDeviceDriverD3D12::_compute_component_mapping(const RDD::TextureView &p_view) {
+	UINT base_swizzle = RD_TO_D3D12_FORMAT[p_view.format].swizzle;
+
+	D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {
+		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.
+		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
+		D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
+		// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.
+		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),
+		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),
+		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),
+		D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),
+	};
+
+	return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
+			p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],
+			p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],
+			p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],
+			p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);
+}
+
+UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits) {
+	TextureAspect aspect = TEXTURE_ASPECT_MAX;
+
+	if (p_aspect_bits.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {
+		DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
+		aspect = TEXTURE_ASPECT_COLOR;
+	}
+	if (p_aspect_bits.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {
+		DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
+		aspect = TEXTURE_ASPECT_DEPTH;
+	}
+	if (p_aspect_bits.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {
+		DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
+		aspect = TEXTURE_ASPECT_STENCIL;
+	}
+
+	DEV_ASSERT(aspect != TEXTURE_ASPECT_MAX);
+
+	return _compute_plane_slice(p_format, aspect);
+}
+
+UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, TextureAspect p_aspect) {
+	switch (p_aspect) {
+		case TEXTURE_ASPECT_COLOR:
+			// The plane must be 0 for the color aspect (assuming the format is a regular color one, which must be the case).
+			return 0;
+		case TEXTURE_ASPECT_DEPTH:
+			// The plane must be 0 for the color or depth aspect
+			return 0;
+		case TEXTURE_ASPECT_STENCIL:
+			// The plane may be 0 for the stencil aspect (if the format is stencil-only), or 1 (if the format is depth-stencil; other cases are ill).
+			return format_get_plane_count(p_format) == 2 ? 1 : 0;
+		default:
+			DEV_ASSERT(false);
+			return 0;
+	}
+}
+
+void RenderingDeviceDriverD3D12::_discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info) {
+	uint32_t planes = 1;
+	if ((p_tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+		planes = format_get_plane_count(p_tex_info->format);
+	}
+	D3D12_DISCARD_REGION dr = {};
+	dr.NumRects = p_cmd_buf_info->render_pass_state.region_is_all ? 0 : 1;
+	dr.pRects = p_cmd_buf_info->render_pass_state.region_is_all ? nullptr : &p_cmd_buf_info->render_pass_state.region_rect;
+	dr.FirstSubresource = UINT_MAX;
+	dr.NumSubresources = 0;
+	for (uint32_t u = 0; u < planes; u++) {
+		for (uint32_t v = 0; v < p_tex_info->layers; v++) {
+			for (uint32_t w = 0; w < p_tex_info->mipmaps; w++) {
+				UINT subresource = D3D12CalcSubresource(
+						p_tex_info->base_mip + w,
+						p_tex_info->base_layer + v,
+						u,
+						p_tex_info->desc.MipLevels,
+						p_tex_info->desc.ArraySize());
+				if (dr.NumSubresources == 0) {
+					dr.FirstSubresource = subresource;
+					dr.NumSubresources = 1;
+				} else if (dr.FirstSubresource + dr.NumSubresources == subresource) {
+					dr.NumSubresources++;
+				} else {
+					p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);
+					dr.FirstSubresource = subresource;
+					dr.NumSubresources = 1;
+				}
+			}
+		}
+	}
+	if (dr.NumSubresources) {
+		p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);
+	}
+}
+
+RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p_format, const TextureView &p_view) {
+	// Using D3D12_RESOURCE_DESC1. Thanks to the layout, it's sliceable down to D3D12_RESOURCE_DESC if needed.
+	CD3DX12_RESOURCE_DESC1 resource_desc = {};
+	resource_desc.Dimension = RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[p_format.texture_type];
+	resource_desc.Alignment = 0; // D3D12MA will override this to use a smaller alignment than the default if possible.
+
+	resource_desc.Width = p_format.width;
+	resource_desc.Height = p_format.height;
+	resource_desc.DepthOrArraySize = p_format.depth * p_format.array_layers;
+	resource_desc.MipLevels = p_format.mipmaps;
+
+	// Format.
+	bool cross_family_sharing = false;
+	bool relaxed_casting_available = false;
+	DXGI_FORMAT *relaxed_casting_formats = nullptr;
+	uint32_t relaxed_casting_format_count = 0;
+	{
+		resource_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].family;
+
+		// If views of different families are wanted, special setup is needed for proper sharing among them.
+		// Two options here:
+		// 1. If ID3DDevice10 is present and driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA).
+		// 2. Otherwise, fall back to an approach based on abusing aliasing, hoping for the best. [[CROSS_FAMILY_ALIASING]]
+		if (p_format.shareable_formats.size()) {
+			if (context->get_format_capabilities().relaxed_casting_supported) {
+				ComPtr<ID3D12Device10> device_10;
+				device->QueryInterface(device_10.GetAddressOf());
+				if (device_10) {
+					relaxed_casting_available = true;
+					relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size());
+					relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format;
+					relaxed_casting_format_count++;
+				}
+			}
+		}
+
+		HashMap<DataFormat, D3D12_RESOURCE_FLAGS> aliases_forbidden_flags;
+		for (int i = 0; i < p_format.shareable_formats.size(); i++) {
+			DataFormat curr_format = p_format.shareable_formats[i];
+			String format_text = "'" + String(FORMAT_NAMES[p_format.format]) + "'";
+
+			ERR_FAIL_COND_V_MSG(RD_TO_D3D12_FORMAT[curr_format].family == DXGI_FORMAT_UNKNOWN, TextureID(), "Format " + format_text + " is not supported.");
+
+			if (RD_TO_D3D12_FORMAT[curr_format].family != RD_TO_D3D12_FORMAT[p_format.format].family) {
+				cross_family_sharing = true;
+				if (!relaxed_casting_available) {
+					break;
+				}
+				relaxed_casting_formats[relaxed_casting_format_count] = RD_TO_D3D12_FORMAT[curr_format].general_format;
+				relaxed_casting_format_count++;
+			}
+		}
+
+		if (cross_family_sharing && !relaxed_casting_available) {
+			// At least guarantee the same layout among aliases.
+			resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
+
+			// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_layout.
+			if (p_format.texture_type == TEXTURE_TYPE_1D) {
+				ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a 1D texture.");
+			}
+			if (p_format.samples != TEXTURE_SAMPLES_1) {
+				ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a multi-sample texture.");
+			}
+			if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+				ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a depth-stencil texture.");
+			}
+			if (RD_TO_D3D12_FORMAT[p_format.format].family == DXGI_FORMAT_R32G32B32_TYPELESS) {
+				ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for an R32G32B32 texture.");
+			}
+		}
+	}
+
+	// Usage.
+	if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
+	} else {
+		if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT)) {
+			resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // For clearing via UAV.
+		}
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
+		resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {
+		// For VRS images we can't use the typeless format.
+		resource_desc.Format = DXGI_FORMAT_R8_UINT;
+	}
+
+	resource_desc.SampleDesc = {};
+	DXGI_FORMAT format_to_test = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ? RD_TO_D3D12_FORMAT[p_format.format].dsv_format : RD_TO_D3D12_FORMAT[p_format.format].general_format;
+	if (!(resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
+		resource_desc.SampleDesc.Count = MIN(
+				_find_max_common_supported_sample_count(format_to_test),
+				TEXTURE_SAMPLES_COUNT[p_format.samples]);
+	} else {
+		// No MSAA in D3D12 if storage. May have become possible recently where supported, though.
+		resource_desc.SampleDesc.Count = 1;
+	}
+	resource_desc.SampleDesc.Quality = resource_desc.SampleDesc.Count == 1 ? 0 : DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
+
+	// Create.
+
+	D3D12MA::ALLOCATION_DESC allocation_desc = {};
+	if (cross_family_sharing && !relaxed_casting_available) {
+		allocation_desc.Flags = D3D12MA::ALLOCATION_FLAG_CAN_ALIAS;
+	}
+	allocation_desc.HeapType = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_DEFAULT;
+	if ((resource_desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) {
+		allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
+	} else {
+		allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
+	}
+	if ((resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
+		allocation_desc.ExtraHeapFlags |= D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS;
+	}
+
+#ifdef USE_SMALL_ALLOCS_POOL
+	uint32_t width = 0, height = 0;
+	uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
+	if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
+		allocation_desc.CustomPool = _find_or_create_small_allocs_pool(allocation_desc.HeapType, allocation_desc.ExtraHeapFlags);
+	}
+#endif
+
+	D3D12_RESOURCE_STATES initial_state = {};
+	ID3D12Resource *texture = nullptr;
+	ComPtr<ID3D12Resource> main_texture;
+	ComPtr<D3D12MA::Allocation> allocation;
+	static const FLOAT black[4] = {};
+	D3D12_CLEAR_VALUE clear_value = CD3DX12_CLEAR_VALUE(RD_TO_D3D12_FORMAT[p_format.format].general_format, black);
+	D3D12_CLEAR_VALUE *clear_value_ptr = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : nullptr;
+	{
+		HRESULT res = E_FAIL;
+		if (cross_family_sharing && relaxed_casting_available) {
+			res = allocator->CreateResource3(
+					&allocation_desc,
+					&resource_desc,
+					D3D12_BARRIER_LAYOUT_COMMON, // Needed for barrier interop.
+					clear_value_ptr,
+					relaxed_casting_format_count,
+					relaxed_casting_formats,
+					allocation.GetAddressOf(),
+					IID_PPV_ARGS(main_texture.GetAddressOf()));
+			initial_state = D3D12_RESOURCE_STATE_COMMON; // Needed for barrier interop.
+		} else {
+			res = allocator->CreateResource(
+					&allocation_desc,
+					(D3D12_RESOURCE_DESC *)&resource_desc,
+					D3D12_RESOURCE_STATE_COPY_DEST,
+					clear_value_ptr,
+					allocation.GetAddressOf(),
+					IID_PPV_ARGS(main_texture.GetAddressOf()));
+			initial_state = D3D12_RESOURCE_STATE_COPY_DEST;
+		}
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), "CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+		texture = main_texture.Get();
+	}
+
+	// Describe views.
+
+	D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+	{
+		srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+		srv_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_format.texture_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_format.texture_type];
+		srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);
+
+		switch (srv_desc.ViewDimension) {
+			case D3D12_SRV_DIMENSION_TEXTURE1D: {
+				srv_desc.Texture1D.MipLevels = p_format.mipmaps;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
+				srv_desc.Texture1DArray.MipLevels = p_format.mipmaps;
+				srv_desc.Texture1DArray.ArraySize = p_format.array_layers;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE2D: {
+				srv_desc.Texture2D.MipLevels = p_format.mipmaps;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
+				srv_desc.Texture2DArray.MipLevels = p_format.mipmaps;
+				srv_desc.Texture2DArray.ArraySize = p_format.array_layers;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
+				srv_desc.Texture2DMSArray.ArraySize = p_format.array_layers;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
+				srv_desc.TextureCubeArray.MipLevels = p_format.mipmaps;
+				srv_desc.TextureCubeArray.NumCubes = p_format.array_layers / 6;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURE3D: {
+				srv_desc.Texture3D.MipLevels = p_format.mipmaps;
+			} break;
+			case D3D12_SRV_DIMENSION_TEXTURECUBE: {
+				srv_desc.TextureCube.MipLevels = p_format.mipmaps;
+			} break;
+			default: {
+			}
+		}
+	}
+
+	D3D12_UNORDERED_ACCESS_VIEW_DESC main_uav_desc = {};
+	{
+		main_uav_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].general_format;
+		main_uav_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_format.texture_type] : D3D12_UAV_DIMENSION_UNKNOWN;
+
+		switch (main_uav_desc.ViewDimension) {
+			case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
+				main_uav_desc.Texture1DArray.ArraySize = p_format.array_layers;
+			} break;
+			case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
+				// Either for an actual 2D texture array, cubemap or cubemap array.
+				main_uav_desc.Texture2DArray.ArraySize = p_format.array_layers;
+			} break;
+			case D3D12_UAV_DIMENSION_TEXTURE3D: {
+				main_uav_desc.Texture3D.WSize = p_format.depth;
+			} break;
+			default: {
+			}
+		}
+	}
+
+	D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = main_uav_desc;
+	uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+
+	// Create aliases if needed. [[CROSS_FAMILY_ALIASING]]
+
+	using AliasEntry = Pair<DXGI_FORMAT, ID3D12Resource *>;
+	AliasEntry *aliases = nullptr;
+	uint32_t alias_count = 0;
+	if (cross_family_sharing && !relaxed_casting_available) {
+		aliases = ALLOCA_ARRAY(AliasEntry, p_format.shareable_formats.size());
+
+		for (int i = 0; i < p_format.shareable_formats.size(); i++) {
+			DataFormat curr_format = p_format.shareable_formats[i];
+
+			DXGI_FORMAT format_family = RD_TO_D3D12_FORMAT[curr_format].family;
+			if (format_family == RD_TO_D3D12_FORMAT[p_format.format].family) {
+				continue;
+			}
+
+			D3D12_RESOURCE_DESC alias_resource_desc = *(D3D12_RESOURCE_DESC *)&resource_desc;
+			alias_resource_desc.Format = format_family;
+			clear_value.Format = format_family;
+			if ((alias_resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
+				if (!texture_get_usages_supported_by_format(curr_format, false).has_flag(TEXTURE_USAGE_STORAGE_BIT)) {
+					alias_resource_desc.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+				}
+			}
+			ID3D12Resource *alias = nullptr;
+			HRESULT res = allocator->CreateAliasingResource(
+					allocation.Get(),
+					0,
+					&alias_resource_desc,
+					initial_state,
+					(alias_resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? clear_value_ptr : nullptr,
+					IID_PPV_ARGS(&alias));
+			if (!SUCCEEDED(res)) {
+				for (uint32_t j = 0; j < alias_count; j++) {
+					aliases[j].second->Release();
+				}
+				ERR_FAIL_V_MSG(TextureID(), "CreateAliasingResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+			}
+			aliases[alias_count] = AliasEntry(format_family, alias);
+			alias_count++;
+
+			if (curr_format == p_view.format) {
+				texture = alias;
+			}
+		}
+	}
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	tex_info->resource = texture;
+	tex_info->owner_info.resource = main_texture;
+	tex_info->owner_info.allocation = allocation;
+	tex_info->owner_info.states.subresource_states.resize(p_format.mipmaps * p_format.array_layers);
+	for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {
+		tex_info->owner_info.states.subresource_states[i] = initial_state;
+	}
+	tex_info->states_ptr = &tex_info->owner_info.states;
+	tex_info->format = p_format.format;
+	tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;
+	tex_info->base_layer = 0;
+	tex_info->layers = resource_desc.ArraySize();
+	tex_info->base_mip = 0;
+	tex_info->mipmaps = resource_desc.MipLevels;
+	tex_info->view_descs.srv = srv_desc;
+	tex_info->view_descs.uav = uav_desc;
+	tex_info->main_texture = main_texture.Get();
+	tex_info->aliasing_hack.main_uav_desc = main_uav_desc;
+	if (alias_count) {
+		for (uint32_t i = 0; i < alias_count; i++) {
+			tex_info->aliasing_hack.owner_info.aliases.insert(aliases[i].first, aliases[i].second);
+		}
+	}
+
+	return TextureID(tex_info);
+}
+
+RDD::TextureID RenderingDeviceDriverD3D12::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) {
+	ERR_FAIL_V_MSG(TextureID(), "Unimplemented!");
+}
+
+RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
+	const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID());
+#endif
+
+	ID3D12Resource *texture = nullptr;
+	if (owner_tex_info->aliasing_hack.owner_info.aliases.is_empty()) {
+		texture = owner_tex_info->resource;
+	} else {
+		texture = owner_tex_info->main_texture;
+		for (const KeyValue<DXGI_FORMAT, ComPtr<ID3D12Resource>> &E : owner_tex_info->aliasing_hack.owner_info.aliases) {
+			if (E.key == RD_TO_D3D12_FORMAT[p_view.format].family) {
+				texture = E.value.Get();
+				break;
+			}
+		}
+	}
+
+	// Describe views.
+
+	D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = owner_tex_info->view_descs.srv;
+	{
+		srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+		srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);
+	}
+
+	D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = owner_tex_info->view_descs.uav;
+	{
+		uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+	}
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	tex_info->resource = texture;
+	tex_info->states_ptr = owner_tex_info->states_ptr;
+	tex_info->format = p_view.format;
+	tex_info->desc = owner_tex_info->desc;
+	tex_info->base_layer = owner_tex_info->base_layer;
+	tex_info->layers = owner_tex_info->layers;
+	tex_info->base_mip = owner_tex_info->base_mip;
+	tex_info->mipmaps = owner_tex_info->mipmaps;
+	tex_info->view_descs.srv = srv_desc;
+	tex_info->view_descs.uav = uav_desc;
+	tex_info->main_texture = owner_tex_info->main_texture;
+	tex_info->aliasing_hack.main_uav_desc = owner_tex_info->aliasing_hack.main_uav_desc;
+
+	return TextureID(tex_info);
+}
+
+RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
+	const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID());
+#endif
+
+	// Find appropriate resource instance.
+
+	ID3D12Resource *texture = nullptr;
+	if (owner_tex_info->aliasing_hack.owner_info.aliases.is_empty()) {
+		texture = owner_tex_info->resource;
+	} else {
+		texture = owner_tex_info->main_texture;
+		for (const KeyValue<DXGI_FORMAT, ComPtr<ID3D12Resource>> &E : owner_tex_info->aliasing_hack.owner_info.aliases) {
+			if (E.key == RD_TO_D3D12_FORMAT[p_view.format].family) {
+				texture = E.value.Get();
+				break;
+			}
+		}
+	}
+
+	// Describe views.
+
+	D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = owner_tex_info->view_descs.srv;
+	{
+		srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+		srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);
+	}
+
+	D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = owner_tex_info->view_descs.uav;
+	{
+		uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
+	}
+
+	// Complete description with slicing.
+	// (Leveraging aliasing in members of the union as much as possible.)
+
+	srv_desc.Texture1D.MostDetailedMip = p_mipmap;
+	srv_desc.Texture1D.MipLevels = 1;
+
+	uav_desc.Texture1D.MipSlice = p_mipmap;
+
+	switch (p_slice_type) {
+		case TEXTURE_SLICE_2D: {
+			if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) {
+				DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D);
+			} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) {
+				DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN);
+			} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) {
+				srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
+				srv_desc.Texture2DArray.FirstArraySlice = p_layer;
+				srv_desc.Texture2DArray.ArraySize = 1;
+				srv_desc.Texture2DArray.PlaneSlice = 0;
+				srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
+
+				uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
+				uav_desc.Texture2DArray.FirstArraySlice = p_layer;
+				uav_desc.Texture2DArray.ArraySize = 1;
+				uav_desc.Texture2DArray.PlaneSlice = 0;
+			} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) {
+				srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
+				srv_desc.Texture2DMSArray.FirstArraySlice = p_layer;
+				srv_desc.Texture2DMSArray.ArraySize = 1;
+
+				uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN;
+			} else {
+				DEV_ASSERT(false);
+			}
+		} break;
+		case TEXTURE_SLICE_CUBEMAP: {
+			if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE) {
+				DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
+			} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) {
+				srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
+
+				DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
+				uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
+				uav_desc.Texture2DArray.FirstArraySlice = 0;
+				uav_desc.Texture2DArray.ArraySize = 6;
+				uav_desc.Texture2DArray.PlaneSlice = 0;
+			} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) {
+				srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
+				srv_desc.TextureCubeArray.First2DArrayFace = p_layer;
+				srv_desc.TextureCubeArray.NumCubes = 1;
+				srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f;
+
+				DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
+				uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
+				uav_desc.Texture2DArray.FirstArraySlice = p_layer;
+				uav_desc.Texture2DArray.ArraySize = 6;
+				uav_desc.Texture2DArray.PlaneSlice = 0;
+			} else {
+				DEV_ASSERT(false);
+			}
+		} break;
+		case TEXTURE_SLICE_3D: {
+			DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D);
+
+			DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D);
+			uav_desc.Texture3D.WSize = -1;
+		} break;
+		case TEXTURE_SLICE_2D_ARRAY: {
+			DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY);
+			srv_desc.Texture2DArray.FirstArraySlice = p_layer;
+			srv_desc.Texture2DArray.ArraySize = p_layers;
+
+			DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
+			uav_desc.Texture2DArray.FirstArraySlice = p_layer;
+			uav_desc.Texture2DArray.ArraySize = p_layers;
+		} break;
+	}
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	tex_info->resource = texture;
+	tex_info->states_ptr = owner_tex_info->states_ptr;
+	tex_info->format = p_view.format;
+	tex_info->desc = owner_tex_info->desc;
+	tex_info->base_layer = p_layer;
+	tex_info->layers = p_layers;
+	tex_info->base_mip = p_mipmap;
+	tex_info->mipmaps = p_mipmaps;
+	tex_info->view_descs.srv = srv_desc;
+	tex_info->view_descs.uav = uav_desc;
+	tex_info->main_texture = owner_tex_info->main_texture;
+	tex_info->aliasing_hack.main_uav_desc = owner_tex_info->aliasing_hack.main_uav_desc;
+
+	return TextureID(tex_info);
+}
+
+void RenderingDeviceDriverD3D12::texture_free(TextureID p_texture) {
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+	VersatileResource::free(resources_allocator, tex_info);
+}
+
+uint64_t RenderingDeviceDriverD3D12::texture_get_allocation_size(TextureID p_texture) {
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+	return tex_info->owner_info.allocation ? tex_info->owner_info.allocation->GetSize() : 0;
+}
+
+void RenderingDeviceDriverD3D12::texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) {
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+
+	UINT subresource = tex_info->desc.CalcSubresource(p_subresource.mipmap, p_subresource.layer, 0);
+
+	D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
+	UINT64 subresource_total_size = 0;
+	device->GetCopyableFootprints(
+			&tex_info->desc,
+			subresource,
+			1,
+			0,
+			&footprint,
+			nullptr,
+			nullptr,
+			&subresource_total_size);
+
+	*r_layout = {};
+	r_layout->offset = footprint.Offset;
+	r_layout->size = subresource_total_size;
+	r_layout->row_pitch = footprint.Footprint.RowPitch;
+	r_layout->depth_pitch = subresource_total_size / tex_info->desc.Depth();
+	r_layout->layer_pitch = subresource_total_size / tex_info->desc.ArraySize();
+}
+
+uint8_t *RenderingDeviceDriverD3D12::texture_map(TextureID p_texture, const TextureSubresource &p_subresource) {
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(tex_info->mapped_subresource != UINT_MAX, nullptr);
+#endif
+
+	UINT plane = _compute_plane_slice(tex_info->format, p_subresource.aspect);
+	UINT subresource = tex_info->desc.CalcSubresource(p_subresource.mipmap, p_subresource.layer, plane);
+
+	void *data_ptr = nullptr;
+	HRESULT res = tex_info->resource->Map(subresource, &VOID_RANGE, &data_ptr);
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	tex_info->mapped_subresource = subresource;
+	return (uint8_t *)data_ptr;
+}
+
+void RenderingDeviceDriverD3D12::texture_unmap(TextureID p_texture) {
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND(tex_info->mapped_subresource == UINT_MAX);
+#endif
+	tex_info->resource->Unmap(tex_info->mapped_subresource, &VOID_RANGE);
+	tex_info->mapped_subresource = UINT_MAX;
+}
+
+BitField<RDD::TextureUsageBits> RenderingDeviceDriverD3D12::texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) {
+	D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
+	srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
+	HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	D3D12_FEATURE_DATA_FORMAT_SUPPORT &uav_support = srv_rtv_support; // Fine for now.
+
+	D3D12_FEATURE_DATA_FORMAT_SUPPORT dsv_support = {};
+	dsv_support.Format = RD_TO_D3D12_FORMAT[p_format].dsv_format;
+	res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dsv_support, sizeof(dsv_support));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	// Everything supported by default makes an all-or-nothing check easier for the caller.
+	BitField<RDD::TextureUsageBits> supported = INT64_MAX;
+
+	// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_format_support1,
+	// as long as the resource can be used as a texture, Sample() will work with point filter at least.
+	// However, we've empirically found that checking for at least D3D12_FORMAT_SUPPORT1_SHADER_LOAD is needed.
+	// That's almost good for integer formats. The problem is that theoretically there may be
+	// float formats that support LOAD but not SAMPLE fully, so this check will not detect
+	// such a flaw in the format. Linearly interpolated sampling would just not work on them.
+	if (!(srv_rtv_support.Support1 & (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) ||
+			RD_TO_D3D12_FORMAT[p_format].general_format == DXGI_FORMAT_UNKNOWN) {
+		supported.clear_flag(TEXTURE_USAGE_SAMPLING_BIT);
+	}
+
+	if (!(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {
+		supported.clear_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
+	}
+	if (!(dsv_support.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {
+		supported.clear_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+	}
+	if (!(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { // Maybe check LOAD/STORE, too?
+		supported.clear_flag(TEXTURE_USAGE_STORAGE_BIT);
+	}
+	if (!(uav_support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD)) { // Check a basic atomic at least.
+		supported.clear_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);
+	}
+	if (RD_TO_D3D12_FORMAT[p_format].general_format != DXGI_FORMAT_R8_UINT) {
+		supported.clear_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT);
+	}
+
+	return supported;
+}
+
+/*****************/
+/**** SAMPLER ****/
+/*****************/
+
+static const D3D12_TEXTURE_ADDRESS_MODE RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[RDD::SAMPLER_REPEAT_MODE_MAX] = {
+	D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+	D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
+	D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
+	D3D12_TEXTURE_ADDRESS_MODE_BORDER,
+	D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
+};
+
+static const FLOAT RD_TO_D3D12_SAMPLER_BORDER_COLOR[RDD::SAMPLER_BORDER_COLOR_MAX][4] = {
+	{ 0, 0, 0, 0 },
+	{ 0, 0, 0, 0 },
+	{ 0, 0, 0, 1 },
+	{ 0, 0, 0, 1 },
+	{ 1, 1, 1, 1 },
+	{ 1, 1, 1, 1 },
+};
+
+RDD::SamplerID RenderingDeviceDriverD3D12::sampler_create(const SamplerState &p_state) {
+	uint32_t slot = UINT32_MAX;
+
+	if (samplers.is_empty()) {
+		// Adding a seemigly busy slot 0 makes things easier elsewhere.
+		samplers.push_back({});
+		samplers.push_back({});
+		slot = 1;
+	} else {
+		for (uint32_t i = 1; i < samplers.size(); i++) {
+			if (samplers[i].Filter == INT_MAX) {
+				slot = i;
+				break;
+			}
+		}
+		if (slot == UINT32_MAX) {
+			slot = samplers.size();
+			samplers.push_back({});
+		}
+	}
+
+	D3D12_SAMPLER_DESC &sampler_desc = samplers[slot];
+
+	if (p_state.use_anisotropy) {
+		sampler_desc.Filter = D3D12_ENCODE_ANISOTROPIC_FILTER(D3D12_FILTER_REDUCTION_TYPE_STANDARD);
+		sampler_desc.MaxAnisotropy = p_state.anisotropy_max;
+	} else {
+		static const D3D12_FILTER_TYPE RD_FILTER_TYPE_TO_D3D12[] = {
+			D3D12_FILTER_TYPE_POINT, // SAMPLER_FILTER_NEAREST.
+			D3D12_FILTER_TYPE_LINEAR, // SAMPLER_FILTER_LINEAR.
+		};
+		sampler_desc.Filter = D3D12_ENCODE_BASIC_FILTER(
+				RD_FILTER_TYPE_TO_D3D12[p_state.min_filter],
+				RD_FILTER_TYPE_TO_D3D12[p_state.mag_filter],
+				RD_FILTER_TYPE_TO_D3D12[p_state.mip_filter],
+				p_state.enable_compare ? D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD);
+	}
+
+	sampler_desc.AddressU = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_u];
+	sampler_desc.AddressV = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_v];
+	sampler_desc.AddressW = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_w];
+
+	for (int i = 0; i < 4; i++) {
+		sampler_desc.BorderColor[i] = RD_TO_D3D12_SAMPLER_BORDER_COLOR[p_state.border_color][i];
+	}
+
+	sampler_desc.MinLOD = p_state.min_lod;
+	sampler_desc.MaxLOD = p_state.max_lod;
+	sampler_desc.MipLODBias = p_state.lod_bias;
+
+	sampler_desc.ComparisonFunc = p_state.enable_compare ? RD_TO_D3D12_COMPARE_OP[p_state.compare_op] : D3D12_COMPARISON_FUNC_NEVER;
+
+	// TODO: Emulate somehow?
+	if (p_state.unnormalized_uvw) {
+		WARN_PRINT("Creating a sampler with unnormalized UVW, which is not supported.");
+	}
+
+	return SamplerID(slot);
+}
+
+void RenderingDeviceDriverD3D12::sampler_free(SamplerID p_sampler) {
+	samplers[p_sampler.id].Filter = (D3D12_FILTER)INT_MAX;
+}
+
+bool RenderingDeviceDriverD3D12::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) {
+	D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
+	srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
+	HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	return (srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE);
+}
+
+/**********************/
+/**** VERTEX ARRAY ****/
+/**********************/
+
+RDD::VertexFormatID RenderingDeviceDriverD3D12::vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) {
+	VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);
+
+	vf_info->input_elem_descs.resize(p_vertex_attribs.size());
+	vf_info->vertex_buffer_strides.resize(p_vertex_attribs.size());
+	for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
+		vf_info->input_elem_descs[i] = {};
+		vf_info->input_elem_descs[i].SemanticName = "TEXCOORD";
+		vf_info->input_elem_descs[i].SemanticIndex = p_vertex_attribs[i].location;
+		vf_info->input_elem_descs[i].Format = RD_TO_D3D12_FORMAT[p_vertex_attribs[i].format].general_format;
+		vf_info->input_elem_descs[i].InputSlot = i; // TODO: Can the same slot be used if data comes from the same buffer (regardless format)?
+		vf_info->input_elem_descs[i].AlignedByteOffset = p_vertex_attribs[i].offset;
+		if (p_vertex_attribs[i].frequency == VERTEX_FREQUENCY_INSTANCE) {
+			vf_info->input_elem_descs[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
+			vf_info->input_elem_descs[i].InstanceDataStepRate = 1;
+		} else {
+			vf_info->input_elem_descs[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
+			vf_info->input_elem_descs[i].InstanceDataStepRate = 0;
+		}
+
+		vf_info->vertex_buffer_strides[i] = p_vertex_attribs[i].stride;
+	}
+
+	return VertexFormatID(vf_info);
+}
+
+void RenderingDeviceDriverD3D12::vertex_format_free(VertexFormatID p_vertex_format) {
+	VertexFormatInfo *vf_info = (VertexFormatInfo *)p_vertex_format.id;
+	VersatileResource::free(resources_allocator, vf_info);
+}
+
+/******************/
+/**** BARRIERS ****/
+/******************/
+
+void RenderingDeviceDriverD3D12::command_pipeline_barrier(
+		CommandBufferID p_cmd_buffer,
+		BitField<RDD::PipelineStageBits> p_src_stages,
+		BitField<RDD::PipelineStageBits> p_dst_stages,
+		VectorView<RDD::MemoryBarrier> p_memory_barriers,
+		VectorView<RDD::BufferBarrier> p_buffer_barriers,
+		VectorView<RDD::TextureBarrier> p_texture_barriers) {
+	if (p_src_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT) && p_dst_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
+		// Looks like the intent is a a full barrier.
+		// In the resource barriers world, we can force a full barrier by discarding some resource, as per
+		// https://microsoft.github.io/DirectX-Specs/d3d/D3D12EnhancedBarriers.html#synchronous-copy-discard-and-resolve.
+		const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+		cmd_buf_info->cmd_list->DiscardResource(frames[frame_idx].aux_resource->GetResource(), nullptr);
+	}
+}
+
+/*************************/
+/**** COMMAND BUFFERS ****/
+/*************************/
+
+// ----- POOL -----
+
+RDD::CommandPoolID RenderingDeviceDriverD3D12::command_pool_create(CommandBufferType p_cmd_buffer_type) {
+	last_command_pool_id.id++;
+	return last_command_pool_id;
+}
+
+void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) {
+	pools_command_buffers.erase(p_cmd_pool);
+}
+
+// ----- BUFFER -----
+
+RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) {
+	D3D12_COMMAND_LIST_TYPE list_type = p_cmd_buffer_type == COMMAND_BUFFER_TYPE_PRIMARY ? D3D12_COMMAND_LIST_TYPE_DIRECT : D3D12_COMMAND_LIST_TYPE_BUNDLE;
+
+	ID3D12CommandAllocator *cmd_allocator = nullptr;
+	{
+		HRESULT res = device->CreateCommandAllocator(list_type, IID_PPV_ARGS(&cmd_allocator));
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	}
+
+	ID3D12GraphicsCommandList *cmd_list = nullptr;
+	{
+		ComPtr<ID3D12Device4> device_4;
+		device->QueryInterface(device_4.GetAddressOf());
+		HRESULT res = E_FAIL;
+		if (device_4) {
+			res = device_4->CreateCommandList1(0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE, IID_PPV_ARGS(&cmd_list));
+		} else {
+			res = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmd_allocator, nullptr, IID_PPV_ARGS(&cmd_list));
+		}
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandList failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+		if (!device_4) {
+			cmd_list->Close();
+		}
+	}
+
+	// Bookkeep
+
+	CommandBufferInfo *cmd_buf_info = VersatileResource::allocate<CommandBufferInfo>(resources_allocator);
+	cmd_buf_info->cmd_allocator = cmd_allocator;
+	cmd_buf_info->cmd_list = cmd_list;
+
+	return CommandBufferID(cmd_buf_info);
+}
+
+bool RenderingDeviceDriverD3D12::command_buffer_begin(CommandBufferID p_cmd_buffer) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(cmd_buf_info->cmd_list->GetType() != D3D12_COMMAND_LIST_TYPE_DIRECT, false);
+#endif
+	HRESULT res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	return true;
+}
+
+bool RenderingDeviceDriverD3D12::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(cmd_buf_info->cmd_list->GetType() != D3D12_COMMAND_LIST_TYPE_BUNDLE, false);
+#endif
+	HRESULT res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	return true;
+}
+
+void RenderingDeviceDriverD3D12::command_buffer_end(CommandBufferID p_cmd_buffer) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	HRESULT res = cmd_buf_info->cmd_list->Close();
+
+	ERR_FAIL_COND_MSG(!SUCCEEDED(res), "Close failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	cmd_buf_info->graphics_pso = nullptr;
+	cmd_buf_info->graphics_root_signature_crc = 0;
+	cmd_buf_info->compute_pso = nullptr;
+	cmd_buf_info->compute_root_signature_crc = 0;
+}
+
+void RenderingDeviceDriverD3D12::command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND(cmd_buf_info->cmd_list->GetType() != D3D12_COMMAND_LIST_TYPE_DIRECT);
+#endif
+	for (uint32_t i = 0; i < p_secondary_cmd_buffers.size(); i++) {
+		const CommandBufferInfo *secondary_cb_info = (const CommandBufferInfo *)p_secondary_cmd_buffers[i].id;
+#ifdef DEBUG_ENABLED
+		ERR_FAIL_COND(secondary_cb_info->cmd_list->GetType() != D3D12_COMMAND_LIST_TYPE_BUNDLE);
+#endif
+		cmd_buf_info->cmd_list->ExecuteBundle(secondary_cb_info->cmd_list.Get());
+	}
+}
+
+/*********************/
+/**** FRAMEBUFFER ****/
+/*********************/
+
+D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceDriverD3D12::_make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {
+	D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {};
+	rtv_desc.Format = p_texture_info->view_descs.srv.Format;
+
+	switch (p_texture_info->view_descs.srv.ViewDimension) {
+		case D3D12_SRV_DIMENSION_TEXTURE1D: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
+			rtv_desc.Texture1D.MipSlice = p_texture_info->base_mip + p_mipmap_offset;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
+			rtv_desc.Texture1DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
+			rtv_desc.Texture1DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
+			rtv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture1DArray.ArraySize : p_layers;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2D: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+			rtv_desc.Texture2D.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
+			rtv_desc.Texture2D.PlaneSlice = p_texture_info->view_descs.srv.Texture2D.PlaneSlice;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
+			rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
+			rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
+			rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DArray.ArraySize : p_layers;
+			rtv_desc.Texture2DArray.PlaneSlice = p_texture_info->view_descs.srv.Texture2DArray.PlaneSlice;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
+			rtv_desc.Texture2DMSArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
+			rtv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize : p_layers;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE3D: {
+			rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
+			rtv_desc.Texture3D.MipSlice = p_texture_info->view_descs.srv.Texture3D.MostDetailedMip + p_mipmap_offset;
+			rtv_desc.Texture3D.FirstWSlice = 0;
+			rtv_desc.Texture3D.WSize = -1;
+		} break;
+		default: {
+			DEV_ASSERT(false);
+		}
+	}
+
+	return rtv_desc;
+}
+
+D3D12_DEPTH_STENCIL_VIEW_DESC RenderingDeviceDriverD3D12::_make_dsv_for_texture(const TextureInfo *p_texture_info) {
+	D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
+	dsv_desc.Format = RD_TO_D3D12_FORMAT[p_texture_info->format].dsv_format;
+	dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
+
+	switch (p_texture_info->view_descs.srv.ViewDimension) {
+		case D3D12_SRV_DIMENSION_TEXTURE1D: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D;
+			dsv_desc.Texture1D.MipSlice = p_texture_info->base_mip;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
+			dsv_desc.Texture1DArray.MipSlice = p_texture_info->base_mip;
+			dsv_desc.Texture1DArray.FirstArraySlice = p_texture_info->base_layer;
+			dsv_desc.Texture1DArray.ArraySize = p_texture_info->view_descs.srv.Texture1DArray.ArraySize;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2D: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
+			dsv_desc.Texture2D.MipSlice = p_texture_info->view_descs.srv.Texture2D.MostDetailedMip;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
+			dsv_desc.Texture2DArray.MipSlice = p_texture_info->base_mip;
+			dsv_desc.Texture2DArray.FirstArraySlice = p_texture_info->base_layer;
+			dsv_desc.Texture2DArray.ArraySize = p_texture_info->view_descs.srv.Texture2DArray.ArraySize;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
+			dsv_desc.Texture2DMS.UnusedField_NothingToDefine = p_texture_info->view_descs.srv.Texture2DMS.UnusedField_NothingToDefine;
+		} break;
+		case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
+			dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
+			dsv_desc.Texture2DMSArray.FirstArraySlice = p_texture_info->base_layer;
+			dsv_desc.Texture2DMSArray.ArraySize = p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize;
+		} break;
+		default: {
+			DEV_ASSERT(false);
+		}
+	}
+
+	return dsv_desc;
+}
+
+RDD::FramebufferID RenderingDeviceDriverD3D12::framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) {
+	// Pre-bookkeep.
+	FramebufferInfo *fb_info = VersatileResource::allocate<FramebufferInfo>(resources_allocator);
+
+	const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
+
+	uint32_t num_color = 0;
+	uint32_t num_depth_stencil = 0;
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;
+		if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+			num_color++;
+		} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+			num_depth_stencil++;
+		}
+	}
+
+	uint32_t vrs_index = UINT32_MAX;
+	for (const Subpass &E : pass_info->subpasses) {
+		if (E.vrs_reference.attachment != AttachmentReference::UNUSED) {
+			vrs_index = E.vrs_reference.attachment;
+		}
+	}
+
+	if (num_color) {
+		Error err = fb_info->rtv_heap.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, num_color, false);
+		if (err) {
+			VersatileResource::free(resources_allocator, fb_info);
+			ERR_FAIL_V(FramebufferID());
+		}
+	}
+	DescriptorsHeap::Walker rtv_heap_walker = fb_info->rtv_heap.make_walker();
+
+	if (num_depth_stencil) {
+		Error err = fb_info->dsv_heap.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, num_depth_stencil, false);
+		if (err) {
+			VersatileResource::free(resources_allocator, fb_info);
+			ERR_FAIL_V(FramebufferID());
+		}
+	}
+	DescriptorsHeap::Walker dsv_heap_walker = fb_info->dsv_heap.make_walker();
+
+	fb_info->attachments_handle_inds.resize(p_attachments.size());
+	fb_info->attachments.reserve(num_color + num_depth_stencil);
+
+	uint32_t color_idx = 0;
+	uint32_t depth_stencil_idx = 0;
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;
+
+		if (fb_info->size.x == 0) {
+			fb_info->size = Size2i(tex_info->desc.Width, tex_info->desc.Height);
+		}
+
+		if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+			D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, 0, 0, UINT32_MAX);
+			device->CreateRenderTargetView(tex_info->resource, &rtv_desc, rtv_heap_walker.get_curr_cpu_handle());
+			rtv_heap_walker.advance();
+
+			fb_info->attachments_handle_inds[i] = color_idx;
+			fb_info->attachments.push_back(p_attachments[i]);
+			color_idx++;
+		} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+			D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(tex_info);
+			device->CreateDepthStencilView(tex_info->resource, &dsv_desc, dsv_heap_walker.get_curr_cpu_handle());
+			dsv_heap_walker.advance();
+
+			fb_info->attachments_handle_inds[i] = depth_stencil_idx;
+			fb_info->attachments.push_back(p_attachments[i]);
+			depth_stencil_idx++;
+		} else if (i == vrs_index) {
+			fb_info->vrs_attachment = p_attachments[i];
+		} else {
+			DEV_ASSERT(false);
+		}
+	}
+
+	DEV_ASSERT(fb_info->attachments.size() == color_idx + depth_stencil_idx);
+	DEV_ASSERT((fb_info->vrs_attachment.id != 0) == (vrs_index != UINT32_MAX));
+
+	DEV_ASSERT(rtv_heap_walker.is_at_eof());
+	DEV_ASSERT(dsv_heap_walker.is_at_eof());
+
+	return FramebufferID(fb_info);
+}
+
+void RenderingDeviceDriverD3D12::framebuffer_free(FramebufferID p_framebuffer) {
+	FramebufferInfo *fb_info = (FramebufferInfo *)p_framebuffer.id;
+	VersatileResource::free(resources_allocator, fb_info);
+}
+
+/****************/
+/**** SHADER ****/
+/****************/
+
+static uint32_t SHADER_STAGES_BIT_OFFSET_INDICES[RenderingDevice::SHADER_STAGE_MAX] = {
+	/* SHADER_STAGE_VERTEX */ 0,
+	/* SHADER_STAGE_FRAGMENT */ 1,
+	/* SHADER_STAGE_TESSELATION_CONTROL */ UINT32_MAX,
+	/* SHADER_STAGE_TESSELATION_EVALUATION */ UINT32_MAX,
+	/* SHADER_STAGE_COMPUTE */ 2,
+};
+
+dxil_validator *RenderingDeviceDriverD3D12::_get_dxil_validator_for_current_thread() {
+	MutexLock lock(dxil_mutex);
+
+	int thread_idx = WorkerThreadPool::get_singleton()->get_thread_index();
+	if (dxil_validators.has(thread_idx)) {
+		return dxil_validators[thread_idx];
+	}
+
+#ifdef DEV_ENABLED
+	print_verbose("Creating DXIL validator for worker thread index " + itos(thread_idx));
+#endif
+
+	dxil_validator *dxil_validator = dxil_create_validator(nullptr);
+	CRASH_COND(!dxil_validator);
+
+	dxil_validators.insert(thread_idx, dxil_validator);
+	return dxil_validator;
+}
+
+uint32_t RenderingDeviceDriverD3D12::_shader_patch_dxil_specialization_constant(
+		PipelineSpecializationConstantType p_type,
+		const void *p_value,
+		const uint64_t (&p_stages_bit_offsets)[D3D12_BITCODE_OFFSETS_NUM_STAGES],
+		HashMap<ShaderStage, Vector<uint8_t>> &r_stages_bytecodes,
+		bool p_is_first_patch) {
+	uint32_t patch_val = 0;
+	switch (p_type) {
+		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT: {
+			uint32_t int_value = *((const int *)p_value);
+			ERR_FAIL_COND_V(int_value & (1 << 31), 0);
+			patch_val = int_value;
+		} break;
+		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL: {
+			bool bool_value = *((const bool *)p_value);
+			patch_val = (uint32_t)bool_value;
+		} break;
+		case PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT: {
+			uint32_t int_value = *((const int *)p_value);
+			ERR_FAIL_COND_V(int_value & (1 << 31), 0);
+			patch_val = (int_value >> 1);
+		} break;
+	}
+	// For VBR encoding to encode the number of bits we expect (32), we need to set the MSB unconditionally.
+	// However, signed VBR moves the MSB to the LSB, so setting the MSB to 1 wouldn't help. Therefore,
+	// the bit we set to 1 is the one at index 30.
+	patch_val |= (1 << 30);
+	patch_val <<= 1; // What signed VBR does.
+
+	auto tamper_bits = [](uint8_t *p_start, uint64_t p_bit_offset, uint64_t p_tb_value) -> uint64_t {
+		uint64_t original = 0;
+		uint32_t curr_input_byte = p_bit_offset / 8;
+		uint8_t curr_input_bit = p_bit_offset % 8;
+		auto get_curr_input_bit = [&]() -> bool {
+			return ((p_start[curr_input_byte] >> curr_input_bit) & 1);
+		};
+		auto move_to_next_input_bit = [&]() {
+			if (curr_input_bit == 7) {
+				curr_input_bit = 0;
+				curr_input_byte++;
+			} else {
+				curr_input_bit++;
+			}
+		};
+		auto tamper_input_bit = [&](bool p_new_bit) {
+			p_start[curr_input_byte] &= ~((uint8_t)1 << curr_input_bit);
+			if (p_new_bit) {
+				p_start[curr_input_byte] |= (uint8_t)1 << curr_input_bit;
+			}
+		};
+		uint8_t value_bit_idx = 0;
+		for (uint32_t i = 0; i < 5; i++) { // 32 bits take 5 full bytes in VBR.
+			for (uint32_t j = 0; j < 7; j++) {
+				bool input_bit = get_curr_input_bit();
+				original |= (uint64_t)(input_bit ? 1 : 0) << value_bit_idx;
+				tamper_input_bit((p_tb_value >> value_bit_idx) & 1);
+				move_to_next_input_bit();
+				value_bit_idx++;
+			}
+#ifdef DEV_ENABLED
+			bool input_bit = get_curr_input_bit();
+			DEV_ASSERT((i < 4 && input_bit) || (i == 4 && !input_bit));
+#endif
+			move_to_next_input_bit();
+		}
+		return original;
+	};
+	uint32_t stages_patched_mask = 0;
+	for (int stage = 0; stage < SHADER_STAGE_MAX; stage++) {
+		if (!r_stages_bytecodes.has((ShaderStage)stage)) {
+			continue;
+		}
+
+		uint64_t offset = p_stages_bit_offsets[SHADER_STAGES_BIT_OFFSET_INDICES[stage]];
+		if (offset == 0) {
+			// This constant does not appear at this stage.
+			continue;
+		}
+
+		Vector<uint8_t> &bytecode = r_stages_bytecodes[(ShaderStage)stage];
+#ifdef DEV_ENABLED
+		uint64_t orig_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val);
+		// Checking against the value the NIR patch should have set.
+		DEV_ASSERT(!p_is_first_patch || ((orig_patch_val >> 1) & GODOT_NIR_SC_SENTINEL_MAGIC_MASK) == GODOT_NIR_SC_SENTINEL_MAGIC);
+		uint64_t readback_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val);
+		DEV_ASSERT(readback_patch_val == patch_val);
+#else
+		tamper_bits(bytecode.ptrw(), offset, patch_val);
+#endif
+
+		stages_patched_mask |= (1 << stage);
+	}
+	return stages_patched_mask;
+}
+
+bool RenderingDeviceDriverD3D12::_shader_apply_specialization_constants(
+		const ShaderInfo *p_shader_info,
+		VectorView<PipelineSpecializationConstant> p_specialization_constants,
+		HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode) {
+	// If something needs to be patched, COW will do the trick.
+	r_final_stages_bytecode = p_shader_info->stages_bytecode;
+	uint32_t stages_re_sign_mask = 0;
+	for (uint32_t i = 0; i < p_specialization_constants.size(); i++) {
+		const PipelineSpecializationConstant &psc = p_specialization_constants[i];
+		if (!(p_shader_info->spirv_specialization_constants_ids_mask & (1 << psc.constant_id))) {
+			// This SC wasn't even in the original SPIR-V shader.
+			continue;
+		}
+		for (const ShaderInfo::SpecializationConstant &sc : p_shader_info->specialization_constants) {
+			if (psc.constant_id == sc.constant_id) {
+				if (psc.int_value != sc.int_value) {
+					stages_re_sign_mask |= _shader_patch_dxil_specialization_constant(psc.type, &psc.int_value, sc.stages_bit_offsets, r_final_stages_bytecode, false);
+				}
+				break;
+			}
+		}
+	}
+	// Re-sign patched stages.
+	for (KeyValue<ShaderStage, Vector<uint8_t>> &E : r_final_stages_bytecode) {
+		ShaderStage stage = E.key;
+		if ((stages_re_sign_mask & (1 << stage))) {
+			Vector<uint8_t> &bytecode = E.value;
+			bool sign_ok = _shader_sign_dxil_bytecode(stage, bytecode);
+			ERR_FAIL_COND_V(!sign_ok, false);
+		}
+	}
+
+	return true;
+}
+
+bool RenderingDeviceDriverD3D12::_shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob) {
+	dxil_validator *validator = _get_dxil_validator_for_current_thread();
+
+	char *err = nullptr;
+	bool res = dxil_validate_module(validator, r_dxil_blob.ptrw(), r_dxil_blob.size(), &err);
+	if (!res) {
+		if (err) {
+			ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(SHADER_STAGE_NAMES[p_stage]) + " failed:\n" + String(err));
+		} else {
+			ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(SHADER_STAGE_NAMES[p_stage]) + " failed.");
+		}
+	}
+
+	return true;
+}
+
+String RenderingDeviceDriverD3D12::shader_get_binary_cache_key() {
+	return "D3D12-SV" + uitos(ShaderBinary::VERSION) + "-" + itos(context->get_shader_capabilities().shader_model);
+}
+
+Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) {
+	ShaderReflection shader_refl;
+	if (_reflect_spirv(p_spirv, shader_refl) != OK) {
+		return Vector<uint8_t>();
+	}
+
+	// Collect reflection data into binary data.
+	ShaderBinary::Data binary_data;
+	Vector<Vector<ShaderBinary::DataBinding>> sets_bindings;
+	Vector<ShaderBinary::SpecializationConstant> specialization_constants;
+	{
+		binary_data.vertex_input_mask = shader_refl.vertex_input_mask;
+		binary_data.fragment_output_mask = shader_refl.fragment_output_mask;
+		binary_data.specialization_constants_count = shader_refl.specialization_constants.size();
+		binary_data.is_compute = shader_refl.is_compute;
+		binary_data.compute_local_size[0] = shader_refl.compute_local_size[0];
+		binary_data.compute_local_size[1] = shader_refl.compute_local_size[1];
+		binary_data.compute_local_size[2] = shader_refl.compute_local_size[2];
+		binary_data.set_count = shader_refl.uniform_sets.size();
+		binary_data.push_constant_size = shader_refl.push_constant_size;
+		binary_data.nir_runtime_data_root_param_idx = UINT32_MAX;
+		binary_data.stage_count = p_spirv.size();
+
+		for (const Vector<ShaderUniform> &spirv_set : shader_refl.uniform_sets) {
+			Vector<ShaderBinary::DataBinding> bindings;
+			for (const ShaderUniform &spirv_uniform : spirv_set) {
+				ShaderBinary::DataBinding binding;
+				binding.type = (uint32_t)spirv_uniform.type;
+				binding.binding = spirv_uniform.binding;
+				binding.stages = (uint32_t)spirv_uniform.stages;
+				binding.length = spirv_uniform.length;
+				binding.writable = (uint32_t)spirv_uniform.writable;
+				bindings.push_back(binding);
+			}
+			sets_bindings.push_back(bindings);
+		}
+
+		for (const ShaderSpecializationConstant &spirv_sc : shader_refl.specialization_constants) {
+			ShaderBinary::SpecializationConstant spec_constant;
+			spec_constant.type = (uint32_t)spirv_sc.type;
+			spec_constant.constant_id = spirv_sc.constant_id;
+			spec_constant.int_value = spirv_sc.int_value;
+			spec_constant.stage_flags = spirv_sc.stages;
+			specialization_constants.push_back(spec_constant);
+
+			binary_data.spirv_specialization_constants_ids_mask |= (1 << spirv_sc.constant_id);
+		}
+	}
+
+	// Translate SPIR-V shaders to DXIL, and collect shader info from the new representation.
+	HashMap<ShaderStage, Vector<uint8_t>> dxil_blobs;
+	BitField<ShaderStage> stages_processed;
+	{
+		HashMap<int, nir_shader *> stages_nir_shaders;
+
+		auto free_nir_shaders = [&]() {
+			for (KeyValue<int, nir_shader *> &E : stages_nir_shaders) {
+				ralloc_free(E.value);
+			}
+			stages_nir_shaders.clear();
+		};
+
+		// This is based on spirv2dxil.c. May need updates when it changes.
+		// Also, this has to stay around until after linking.
+		nir_shader_compiler_options nir_options = *dxil_get_nir_compiler_options();
+		nir_options.lower_base_vertex = false;
+
+		dxil_spirv_runtime_conf dxil_runtime_conf = {};
+		dxil_runtime_conf.runtime_data_cbv.register_space = RUNTIME_DATA_SPACE;
+		dxil_runtime_conf.runtime_data_cbv.base_shader_register = RUNTIME_DATA_REGISTER;
+		dxil_runtime_conf.push_constant_cbv.register_space = ROOT_CONSTANT_SPACE;
+		dxil_runtime_conf.push_constant_cbv.base_shader_register = ROOT_CONSTANT_REGISTER;
+		dxil_runtime_conf.zero_based_vertex_instance_id = true;
+		dxil_runtime_conf.zero_based_compute_workgroup_id = true;
+		dxil_runtime_conf.declared_read_only_images_as_srvs = true;
+		// Making this explicit to let maintainers know that in practice this didn't improve performance,
+		// probably because data generated by one shader and consumed by another one forces the resource
+		// to transition from UAV to SRV, and back, instead of being an UAV all the time.
+		// In case someone wants to try, care must be taken so in case of incompatible bindings across stages
+		// happen as a result, all the stages are re-translated. That can happen if, for instance, a stage only
+		// uses an allegedly writable resource only for reading but the next stage doesn't.
+		dxil_runtime_conf.inferred_read_only_images_as_srvs = false;
+
+		// - Translate SPIR-V to NIR.
+		for (uint32_t i = 0; i < p_spirv.size(); i++) {
+			ShaderStage stage = (ShaderStage)p_spirv[i].shader_stage;
+			ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage);
+
+			stages_processed.set_flag(stage_flag);
+
+			{
+				const char *entry_point = "main";
+
+				static const gl_shader_stage SPIRV_TO_MESA_STAGES[SHADER_STAGE_MAX] = {
+					/* SHADER_STAGE_VERTEX */ MESA_SHADER_VERTEX,
+					/* SHADER_STAGE_FRAGMENT */ MESA_SHADER_FRAGMENT,
+					/* SHADER_STAGE_TESSELATION_CONTROL */ MESA_SHADER_TESS_CTRL,
+					/* SHADER_STAGE_TESSELATION_EVALUATION */ MESA_SHADER_TESS_EVAL,
+					/* SHADER_STAGE_COMPUTE */ MESA_SHADER_COMPUTE,
+				};
+
+				nir_shader *shader = spirv_to_nir(
+						(const uint32_t *)p_spirv[i].spirv.ptr(),
+						p_spirv[i].spirv.size() / sizeof(uint32_t),
+						nullptr,
+						0,
+						SPIRV_TO_MESA_STAGES[stage],
+						entry_point,
+						dxil_spirv_nir_get_spirv_options(), &nir_options);
+				if (!shader) {
+					free_nir_shaders();
+					ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader translation (step 1) at stage " + String(SHADER_STAGE_NAMES[stage]) + " failed.");
+				}
+
+#ifdef DEV_ENABLED
+				nir_validate_shader(shader, "Validate before feeding NIR to the DXIL compiler");
+#endif
+
+				if (stage == SHADER_STAGE_VERTEX) {
+					dxil_runtime_conf.yz_flip.y_mask = 0xffff;
+					dxil_runtime_conf.yz_flip.mode = DXIL_SPIRV_Y_FLIP_UNCONDITIONAL;
+				} else {
+					dxil_runtime_conf.yz_flip.y_mask = 0;
+					dxil_runtime_conf.yz_flip.mode = DXIL_SPIRV_YZ_FLIP_NONE;
+				}
+
+				// This is based on spirv2dxil.c. May need updates when it changes.
+				dxil_spirv_nir_prep(shader);
+				bool requires_runtime_data = {};
+				dxil_spirv_nir_passes(shader, &dxil_runtime_conf, &requires_runtime_data);
+
+				stages_nir_shaders[stage] = shader;
+			}
+		}
+
+		// - Link NIR shaders.
+		for (int i = SHADER_STAGE_MAX - 1; i >= 0; i--) {
+			if (!stages_nir_shaders.has(i)) {
+				continue;
+			}
+			nir_shader *shader = stages_nir_shaders[i];
+			nir_shader *prev_shader = nullptr;
+			for (int j = i - 1; j >= 0; j--) {
+				if (stages_nir_shaders.has(j)) {
+					prev_shader = stages_nir_shaders[j];
+					break;
+				}
+			}
+			if (prev_shader) {
+				bool requires_runtime_data = {};
+				dxil_spirv_nir_link(shader, prev_shader, &dxil_runtime_conf, &requires_runtime_data);
+			}
+		}
+
+		// - Translate NIR to DXIL.
+		for (uint32_t i = 0; i < p_spirv.size(); i++) {
+			ShaderStage stage = (ShaderStage)p_spirv[i].shader_stage;
+
+			struct ShaderData {
+				ShaderStage stage;
+				ShaderBinary::Data &binary_data;
+				Vector<Vector<ShaderBinary::DataBinding>> &sets_bindings;
+				Vector<ShaderBinary::SpecializationConstant> &specialization_constants;
+			} shader_data{ stage, binary_data, sets_bindings, specialization_constants };
+
+			GodotNirCallbacks godot_nir_callbacks = {};
+			godot_nir_callbacks.data = &shader_data;
+
+			godot_nir_callbacks.report_resource = [](uint32_t p_register, uint32_t p_space, uint32_t p_dxil_type, void *p_data) {
+				ShaderData &shader_data_in = *(ShaderData *)p_data;
+
+				// Types based on Mesa's dxil_container.h.
+				static const uint32_t DXIL_RES_SAMPLER = 1;
+				static const ResourceClass DXIL_TYPE_TO_CLASS[] = {
+					/* DXIL_RES_INVALID */ RES_CLASS_INVALID,
+					/* DXIL_RES_SAMPLER */ RES_CLASS_INVALID, // Handling sampler as a flag.
+					/* DXIL_RES_CBV */ RES_CLASS_CBV,
+					/* DXIL_RES_SRV_TYPED */ RES_CLASS_SRV,
+					/* DXIL_RES_SRV_RAW */ RES_CLASS_SRV,
+					/* DXIL_RES_SRV_STRUCTURED */ RES_CLASS_SRV,
+					/* DXIL_RES_UAV_TYPED */ RES_CLASS_UAV,
+					/* DXIL_RES_UAV_RAW */ RES_CLASS_UAV,
+					/* DXIL_RES_UAV_STRUCTURED */ RES_CLASS_UAV,
+					/* DXIL_RES_UAV_STRUCTURED_WITH_COUNTER */ RES_CLASS_INVALID,
+				};
+				DEV_ASSERT(p_dxil_type < ARRAY_SIZE(DXIL_TYPE_TO_CLASS));
+				ResourceClass res_class = DXIL_TYPE_TO_CLASS[p_dxil_type];
+
+				if (p_register == ROOT_CONSTANT_REGISTER && p_space == ROOT_CONSTANT_SPACE) {
+					DEV_ASSERT(res_class == RES_CLASS_CBV);
+					shader_data_in.binary_data.dxil_push_constant_stages |= (1 << shader_data_in.stage);
+				} else if (p_register == RUNTIME_DATA_REGISTER && p_space == RUNTIME_DATA_SPACE) {
+					DEV_ASSERT(res_class == RES_CLASS_CBV);
+					shader_data_in.binary_data.nir_runtime_data_root_param_idx = 1; // Temporary, to be determined later.
+				} else {
+					DEV_ASSERT(p_space == 0);
+
+					uint32_t set = p_register / GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER;
+					uint32_t binding = (p_register % GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER) / GODOT_NIR_BINDING_MULTIPLIER;
+
+					DEV_ASSERT(set < (uint32_t)shader_data_in.sets_bindings.size());
+					bool found = false;
+					for (int j = 0; j < shader_data_in.sets_bindings[set].size(); j++) {
+						if (shader_data_in.sets_bindings[set][j].binding != binding) {
+							continue;
+						}
+
+						ShaderBinary::DataBinding &binding_info = shader_data_in.sets_bindings.write[set].write[j];
+
+						binding_info.dxil_stages |= (1 << shader_data_in.stage);
+
+						if (res_class != RES_CLASS_INVALID) {
+							DEV_ASSERT(binding_info.res_class == (uint32_t)RES_CLASS_INVALID || binding_info.res_class == (uint32_t)res_class);
+							binding_info.res_class = res_class;
+						} else if (p_dxil_type == DXIL_RES_SAMPLER) {
+							binding_info.has_sampler = (uint32_t) true;
+						} else {
+							CRASH_NOW();
+						}
+
+						found = true;
+						break;
+					}
+					DEV_ASSERT(found);
+				}
+			};
+
+			godot_nir_callbacks.report_sc_bit_offset_fn = [](uint32_t p_sc_id, uint64_t p_bit_offset, void *p_data) {
+				ShaderData &shader_data_in = *(ShaderData *)p_data;
+
+				bool found = false;
+				for (int j = 0; j < shader_data_in.specialization_constants.size(); j++) {
+					if (shader_data_in.specialization_constants[j].constant_id != p_sc_id) {
+						continue;
+					}
+
+					uint32_t offset_idx = SHADER_STAGES_BIT_OFFSET_INDICES[shader_data_in.stage];
+					DEV_ASSERT(shader_data_in.specialization_constants.write[j].stages_bit_offsets[offset_idx] == 0);
+					shader_data_in.specialization_constants.write[j].stages_bit_offsets[offset_idx] = p_bit_offset;
+
+					found = true;
+					break;
+				}
+				DEV_ASSERT(found);
+			};
+
+			godot_nir_callbacks.report_bitcode_bit_offset_fn = [](uint64_t p_bit_offset, void *p_data) {
+				DEV_ASSERT(p_bit_offset % 8 == 0);
+				ShaderData &shader_data_in = *(ShaderData *)p_data;
+				uint32_t offset_idx = SHADER_STAGES_BIT_OFFSET_INDICES[shader_data_in.stage];
+				for (int j = 0; j < shader_data_in.specialization_constants.size(); j++) {
+					if (shader_data_in.specialization_constants.write[j].stages_bit_offsets[offset_idx] == 0) {
+						// This SC has been optimized out from this stage.
+						continue;
+					}
+					shader_data_in.specialization_constants.write[j].stages_bit_offsets[offset_idx] += p_bit_offset;
+				}
+			};
+
+			auto shader_model_d3d_to_dxil = [](D3D_SHADER_MODEL p_d3d_shader_model) -> dxil_shader_model {
+				static_assert(SHADER_MODEL_6_0 == 0x60000);
+				static_assert(SHADER_MODEL_6_3 == 0x60003);
+				static_assert(D3D_SHADER_MODEL_6_0 == 0x60);
+				static_assert(D3D_SHADER_MODEL_6_3 == 0x63);
+				return (dxil_shader_model)((p_d3d_shader_model >> 4) * 0x10000 + (p_d3d_shader_model & 0xf));
+			};
+
+			nir_to_dxil_options nir_to_dxil_options = {};
+			nir_to_dxil_options.environment = DXIL_ENVIRONMENT_VULKAN;
+			nir_to_dxil_options.shader_model_max = shader_model_d3d_to_dxil(context->get_shader_capabilities().shader_model);
+			nir_to_dxil_options.validator_version_max = dxil_get_validator_version(_get_dxil_validator_for_current_thread());
+			nir_to_dxil_options.godot_nir_callbacks = &godot_nir_callbacks;
+
+			dxil_logger logger = {};
+			logger.log = [](void *p_priv, const char *p_msg) {
+#ifdef DEBUG_ENABLED
+				print_verbose(p_msg);
+#endif
+			};
+
+			blob dxil_blob = {};
+			bool ok = nir_to_dxil(stages_nir_shaders[stage], &nir_to_dxil_options, &logger, &dxil_blob);
+			ralloc_free(stages_nir_shaders[stage]);
+			stages_nir_shaders.erase(stage);
+			if (!ok) {
+				free_nir_shaders();
+				ERR_FAIL_V_MSG(Vector<uint8_t>(), "Shader translation at stage " + String(SHADER_STAGE_NAMES[stage]) + " failed.");
+			}
+
+			Vector<uint8_t> blob_copy;
+			blob_copy.resize(dxil_blob.size);
+			memcpy(blob_copy.ptrw(), dxil_blob.data, dxil_blob.size);
+			blob_finish(&dxil_blob);
+			dxil_blobs.insert(stage, blob_copy);
+		}
+	}
+
+#if 0
+	if (dxil_blobs.has(SHADER_STAGE_FRAGMENT)) {
+		Ref<FileAccess> f = FileAccess::open("res://1.dxil", FileAccess::WRITE);
+		f->store_buffer(dxil_blobs[SHADER_STAGE_FRAGMENT].ptr(), dxil_blobs[SHADER_STAGE_FRAGMENT].size());
+	}
+#endif
+
+	// Patch with default values of specialization constants.
+	if (specialization_constants.size()) {
+		for (const ShaderBinary::SpecializationConstant &sc : specialization_constants) {
+			_shader_patch_dxil_specialization_constant((PipelineSpecializationConstantType)sc.type, &sc.int_value, sc.stages_bit_offsets, dxil_blobs, true);
+		}
+#if 0
+		if (dxil_blobs.has(SHADER_STAGE_FRAGMENT)) {
+			Ref<FileAccess> f = FileAccess::open("res://2.dxil", FileAccess::WRITE);
+			f->store_buffer(dxil_blobs[SHADER_STAGE_FRAGMENT].ptr(), dxil_blobs[SHADER_STAGE_FRAGMENT].size());
+		}
+#endif
+	}
+
+	// Sign.
+	for (KeyValue<ShaderStage, Vector<uint8_t>> &E : dxil_blobs) {
+		ShaderStage stage = E.key;
+		Vector<uint8_t> &dxil_blob = E.value;
+		bool sign_ok = _shader_sign_dxil_bytecode(stage, dxil_blob);
+		ERR_FAIL_COND_V(!sign_ok, Vector<uint8_t>());
+	}
+
+	// Build the root signature.
+	ComPtr<ID3DBlob> root_sig_blob;
+	{
+		auto stages_to_d3d12_visibility = [](uint32_t p_stages_mask) -> D3D12_SHADER_VISIBILITY {
+			switch (p_stages_mask) {
+				case SHADER_STAGE_VERTEX_BIT: {
+					return D3D12_SHADER_VISIBILITY_VERTEX;
+				}
+				case SHADER_STAGE_FRAGMENT_BIT: {
+					return D3D12_SHADER_VISIBILITY_PIXEL;
+				}
+				default: {
+					return D3D12_SHADER_VISIBILITY_ALL;
+				}
+			}
+		};
+
+		LocalVector<D3D12_ROOT_PARAMETER1> root_params;
+
+		// Root (push) constants.
+		if (binary_data.dxil_push_constant_stages) {
+			CD3DX12_ROOT_PARAMETER1 push_constant;
+			push_constant.InitAsConstants(
+					binary_data.push_constant_size / sizeof(uint32_t),
+					ROOT_CONSTANT_REGISTER,
+					ROOT_CONSTANT_SPACE,
+					stages_to_d3d12_visibility(binary_data.dxil_push_constant_stages));
+			root_params.push_back(push_constant);
+		}
+
+		// NIR-DXIL runtime data.
+		if (binary_data.nir_runtime_data_root_param_idx == 1) { // Set above to 1 when discovering runtime data is needed.
+			DEV_ASSERT(!binary_data.is_compute); // Could be supported if needed, but it's pointless as of now.
+			binary_data.nir_runtime_data_root_param_idx = root_params.size();
+			CD3DX12_ROOT_PARAMETER1 nir_runtime_data;
+			nir_runtime_data.InitAsConstants(
+					sizeof(dxil_spirv_vertex_runtime_data) / sizeof(uint32_t),
+					RUNTIME_DATA_REGISTER,
+					RUNTIME_DATA_SPACE,
+					D3D12_SHADER_VISIBILITY_VERTEX);
+			root_params.push_back(nir_runtime_data);
+		}
+
+		// Descriptor tables (up to two per uniform set, for resources and/or samplers).
+
+		// These have to stay around until serialization!
+		struct TraceableDescriptorTable {
+			uint32_t stages_mask = {};
+			Vector<D3D12_DESCRIPTOR_RANGE1> ranges;
+			Vector<ShaderBinary::DataBinding::RootSignatureLocation *> root_sig_locations;
+		};
+		Vector<TraceableDescriptorTable> resource_tables_maps;
+		Vector<TraceableDescriptorTable> sampler_tables_maps;
+
+		for (int set = 0; set < sets_bindings.size(); set++) {
+			bool first_resource_in_set = true;
+			bool first_sampler_in_set = true;
+			sets_bindings.write[set].sort();
+			for (int i = 0; i < sets_bindings[set].size(); i++) {
+				const ShaderBinary::DataBinding &binding = sets_bindings[set][i];
+
+				bool really_used = binding.dxil_stages != 0;
+#ifdef DEV_ENABLED
+				bool anybody_home = (ResourceClass)binding.res_class != RES_CLASS_INVALID || binding.has_sampler;
+				DEV_ASSERT(anybody_home == really_used);
+#endif
+				if (!really_used) {
+					continue; // Existed in SPIR-V; went away in DXIL.
+				}
+
+				auto insert_range = [](D3D12_DESCRIPTOR_RANGE_TYPE p_range_type,
+											uint32_t p_num_descriptors,
+											uint32_t p_dxil_register,
+											uint32_t p_dxil_stages_mask,
+											ShaderBinary::DataBinding::RootSignatureLocation(&p_root_sig_locations),
+											Vector<TraceableDescriptorTable> &r_tables,
+											bool &r_first_in_set) {
+					if (r_first_in_set) {
+						r_tables.resize(r_tables.size() + 1);
+						r_first_in_set = false;
+					}
+					TraceableDescriptorTable &table = r_tables.write[r_tables.size() - 1];
+					table.stages_mask |= p_dxil_stages_mask;
+
+					CD3DX12_DESCRIPTOR_RANGE1 range;
+					// Due to the aliasing hack for SRV-UAV of different families,
+					// we can be causing an unintended change of data (sometimes the validation layers catch it).
+					D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
+					if (p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) {
+						flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
+					} else if (p_range_type == D3D12_DESCRIPTOR_RANGE_TYPE_CBV) {
+						flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE;
+					}
+					range.Init(p_range_type, p_num_descriptors, p_dxil_register, 0, flags);
+
+					table.ranges.push_back(range);
+					table.root_sig_locations.push_back(&p_root_sig_locations);
+				};
+
+				uint32_t num_descriptors = 1;
+
+				D3D12_DESCRIPTOR_RANGE_TYPE resource_range_type = {};
+				switch ((ResourceClass)binding.res_class) {
+					case RES_CLASS_INVALID: {
+						num_descriptors = binding.length;
+						DEV_ASSERT(binding.has_sampler);
+					} break;
+					case RES_CLASS_CBV: {
+						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+						DEV_ASSERT(!binding.has_sampler);
+					} break;
+					case RES_CLASS_SRV: {
+						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+						num_descriptors = MAX(1u, binding.length); // An unbound R/O buffer is reflected as zero-size.
+					} break;
+					case RES_CLASS_UAV: {
+						resource_range_type = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+						num_descriptors = MAX(1u, binding.length); // An unbound R/W buffer is reflected as zero-size.
+						DEV_ASSERT(!binding.has_sampler);
+					} break;
+				}
+
+				uint32_t dxil_register = set * GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER + binding.binding * GODOT_NIR_BINDING_MULTIPLIER;
+
+				if (binding.res_class != RES_CLASS_INVALID) {
+					insert_range(
+							resource_range_type,
+							num_descriptors,
+							dxil_register,
+							sets_bindings[set][i].dxil_stages,
+							sets_bindings.write[set].write[i].root_sig_locations[RS_LOC_TYPE_RESOURCE],
+							resource_tables_maps,
+							first_resource_in_set);
+				}
+				if (binding.has_sampler) {
+					insert_range(
+							D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
+							num_descriptors,
+							dxil_register,
+							sets_bindings[set][i].dxil_stages,
+							sets_bindings.write[set].write[i].root_sig_locations[RS_LOC_TYPE_SAMPLER],
+							sampler_tables_maps,
+							first_sampler_in_set);
+				}
+			}
+		}
+
+		auto make_descriptor_tables = [&root_params, &stages_to_d3d12_visibility](const Vector<TraceableDescriptorTable> &p_tables) {
+			for (const TraceableDescriptorTable &table : p_tables) {
+				D3D12_SHADER_VISIBILITY visibility = stages_to_d3d12_visibility(table.stages_mask);
+				DEV_ASSERT(table.ranges.size() == table.root_sig_locations.size());
+				for (int i = 0; i < table.ranges.size(); i++) {
+					// By now we know very well which root signature location corresponds to the pointed uniform.
+					table.root_sig_locations[i]->root_param_idx = root_params.size();
+					table.root_sig_locations[i]->range_idx = i;
+				}
+
+				CD3DX12_ROOT_PARAMETER1 root_table;
+				root_table.InitAsDescriptorTable(table.ranges.size(), table.ranges.ptr(), visibility);
+				root_params.push_back(root_table);
+			}
+		};
+
+		make_descriptor_tables(resource_tables_maps);
+		make_descriptor_tables(sampler_tables_maps);
+
+		CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {};
+		D3D12_ROOT_SIGNATURE_FLAGS root_sig_flags =
+				D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
+				D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
+				D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
+				D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |
+				D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS;
+		if (!stages_processed.has_flag(SHADER_STAGE_VERTEX_BIT)) {
+			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS;
+		}
+		if (!stages_processed.has_flag(SHADER_STAGE_FRAGMENT_BIT)) {
+			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
+		}
+		if (binary_data.vertex_input_mask) {
+			root_sig_flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+		}
+		root_sig_desc.Init_1_1(root_params.size(), root_params.ptr(), 0, nullptr, root_sig_flags);
+
+		ComPtr<ID3DBlob> error_blob;
+		HRESULT res = D3DX12SerializeVersionedRootSignature(&root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf());
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), Vector<uint8_t>(),
+				"Serialization of root signature failed with error " + vformat("0x%08ux", (uint64_t)res) + " and the following message:\n" + String((char *)error_blob->GetBufferPointer(), error_blob->GetBufferSize()));
+
+		binary_data.root_signature_crc = crc32(0, nullptr, 0);
+		binary_data.root_signature_crc = crc32(binary_data.root_signature_crc, (const Bytef *)root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize());
+	}
+
+	Vector<Vector<uint8_t>> compressed_stages;
+	Vector<uint32_t> zstd_size;
+
+	uint32_t stages_binary_size = 0;
+
+	for (uint32_t i = 0; i < p_spirv.size(); i++) {
+		Vector<uint8_t> zstd;
+		Vector<uint8_t> &dxil_blob = dxil_blobs[p_spirv[i].shader_stage];
+		zstd.resize(Compression::get_max_compressed_buffer_size(dxil_blob.size(), Compression::MODE_ZSTD));
+		int dst_size = Compression::compress(zstd.ptrw(), dxil_blob.ptr(), dxil_blob.size(), Compression::MODE_ZSTD);
+
+		zstd_size.push_back(dst_size);
+		zstd.resize(dst_size);
+		compressed_stages.push_back(zstd);
+
+		uint32_t s = compressed_stages[i].size();
+		if (s % 4 != 0) {
+			s += 4 - (s % 4);
+		}
+		stages_binary_size += s;
+	}
+
+	CharString shader_name_utf = p_shader_name.utf8();
+
+	binary_data.shader_name_len = shader_name_utf.length();
+
+	uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
+	total_size += sizeof(ShaderBinary::Data);
+
+	total_size += binary_data.shader_name_len;
+	if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+		total_size += 4 - (binary_data.shader_name_len % 4);
+	}
+
+	for (int i = 0; i < sets_bindings.size(); i++) {
+		total_size += sizeof(uint32_t);
+		total_size += sets_bindings[i].size() * sizeof(ShaderBinary::DataBinding);
+	}
+
+	total_size += sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size();
+
+	total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
+	total_size += stages_binary_size;
+
+	binary_data.root_signature_len = root_sig_blob->GetBufferSize();
+	total_size += binary_data.root_signature_len;
+
+	Vector<uint8_t> ret;
+	ret.resize(total_size);
+	{
+		uint32_t offset = 0;
+		uint8_t *binptr = ret.ptrw();
+		binptr[0] = 'G';
+		binptr[1] = 'S';
+		binptr[2] = 'B';
+		binptr[3] = 'D'; // Godot shader binary data.
+		offset += 4;
+		encode_uint32(ShaderBinary::VERSION, binptr + offset);
+		offset += sizeof(uint32_t);
+		encode_uint32(sizeof(ShaderBinary::Data), binptr + offset);
+		offset += sizeof(uint32_t);
+		memcpy(binptr + offset, &binary_data, sizeof(ShaderBinary::Data));
+		offset += sizeof(ShaderBinary::Data);
+
+		if (binary_data.shader_name_len > 0) {
+			memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
+			offset += binary_data.shader_name_len;
+
+			if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+				offset += 4 - (binary_data.shader_name_len % 4);
+			}
+		}
+
+		for (int i = 0; i < sets_bindings.size(); i++) {
+			int count = sets_bindings[i].size();
+			encode_uint32(count, binptr + offset);
+			offset += sizeof(uint32_t);
+			if (count > 0) {
+				memcpy(binptr + offset, sets_bindings[i].ptr(), sizeof(ShaderBinary::DataBinding) * count);
+				offset += sizeof(ShaderBinary::DataBinding) * count;
+			}
+		}
+
+		if (specialization_constants.size()) {
+			memcpy(binptr + offset, specialization_constants.ptr(), sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size());
+			offset += sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size();
+		}
+
+		for (int i = 0; i < compressed_stages.size(); i++) {
+			encode_uint32(p_spirv[i].shader_stage, binptr + offset);
+			offset += sizeof(uint32_t);
+			encode_uint32(dxil_blobs[p_spirv[i].shader_stage].size(), binptr + offset);
+			offset += sizeof(uint32_t);
+			encode_uint32(zstd_size[i], binptr + offset);
+			offset += sizeof(uint32_t);
+			memcpy(binptr + offset, compressed_stages[i].ptr(), compressed_stages[i].size());
+
+			uint32_t s = compressed_stages[i].size();
+
+			if (s % 4 != 0) {
+				s += 4 - (s % 4);
+			}
+
+			offset += s;
+		}
+
+		memcpy(binptr + offset, root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize());
+		offset += root_sig_blob->GetBufferSize();
+
+		ERR_FAIL_COND_V(offset != (uint32_t)ret.size(), Vector<uint8_t>());
+	}
+
+	return ret;
+}
+
+RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) {
+	r_shader_desc = {}; // Driver-agnostic.
+	ShaderInfo shader_info_in; // Driver-specific.
+
+	const uint8_t *binptr = p_shader_binary.ptr();
+	uint32_t binsize = p_shader_binary.size();
+
+	uint32_t read_offset = 0;
+
+	// Consistency check.
+	ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(ShaderBinary::Data), ShaderID());
+	ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', ShaderID());
+
+	uint32_t bin_version = decode_uint32(binptr + 4);
+	ERR_FAIL_COND_V(bin_version != ShaderBinary::VERSION, ShaderID());
+
+	uint32_t bin_data_size = decode_uint32(binptr + 8);
+
+	const ShaderBinary::Data &binary_data = *(reinterpret_cast<const ShaderBinary::Data *>(binptr + 12));
+
+	r_shader_desc.push_constant_size = binary_data.push_constant_size;
+	shader_info_in.dxil_push_constant_size = binary_data.dxil_push_constant_stages ? binary_data.push_constant_size : 0;
+	shader_info_in.nir_runtime_data_root_param_idx = binary_data.nir_runtime_data_root_param_idx;
+
+	r_shader_desc.vertex_input_mask = binary_data.vertex_input_mask;
+	r_shader_desc.fragment_output_mask = binary_data.fragment_output_mask;
+
+	r_shader_desc.is_compute = binary_data.is_compute;
+	shader_info_in.is_compute = binary_data.is_compute;
+	r_shader_desc.compute_local_size[0] = binary_data.compute_local_size[0];
+	r_shader_desc.compute_local_size[1] = binary_data.compute_local_size[1];
+	r_shader_desc.compute_local_size[2] = binary_data.compute_local_size[2];
+
+	read_offset += sizeof(uint32_t) * 3 + bin_data_size;
+
+	if (binary_data.shader_name_len) {
+		r_name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
+		read_offset += binary_data.shader_name_len;
+		if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+			read_offset += 4 - (binary_data.shader_name_len % 4);
+		}
+	}
+
+	r_shader_desc.uniform_sets.resize(binary_data.set_count);
+	shader_info_in.sets.resize(binary_data.set_count);
+
+	for (uint32_t i = 0; i < binary_data.set_count; i++) {
+		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, ShaderID());
+		uint32_t set_count = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		const ShaderBinary::DataBinding *set_ptr = reinterpret_cast<const ShaderBinary::DataBinding *>(binptr + read_offset);
+		uint32_t set_size = set_count * sizeof(ShaderBinary::DataBinding);
+		ERR_FAIL_COND_V(read_offset + set_size >= binsize, ShaderID());
+
+		shader_info_in.sets[i].bindings.reserve(set_count);
+
+		for (uint32_t j = 0; j < set_count; j++) {
+			ShaderUniform info;
+			info.type = UniformType(set_ptr[j].type);
+			info.writable = set_ptr[j].writable;
+			info.length = set_ptr[j].length;
+			info.binding = set_ptr[j].binding;
+
+			ShaderInfo::UniformBindingInfo binding;
+			binding.stages = set_ptr[j].dxil_stages;
+			binding.res_class = (ResourceClass)set_ptr[j].res_class;
+			binding.type = info.type;
+			binding.length = info.length;
+#ifdef DEV_ENABLED
+			binding.writable = set_ptr[j].writable;
+#endif
+			static_assert(sizeof(ShaderInfo::UniformBindingInfo::root_sig_locations) == sizeof(ShaderBinary::DataBinding::root_sig_locations));
+			memcpy((void *)&binding.root_sig_locations, (void *)&set_ptr[j].root_sig_locations, sizeof(ShaderInfo::UniformBindingInfo::root_sig_locations));
+
+			if (binding.root_sig_locations.resource.root_param_idx != UINT32_MAX) {
+				shader_info_in.sets[i].num_root_params.resources++;
+			}
+			if (binding.root_sig_locations.sampler.root_param_idx != UINT32_MAX) {
+				shader_info_in.sets[i].num_root_params.samplers++;
+			}
+
+			r_shader_desc.uniform_sets.write[i].push_back(info);
+			shader_info_in.sets[i].bindings.push_back(binding);
+		}
+
+		read_offset += set_size;
+	}
+
+	ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(ShaderBinary::SpecializationConstant) >= binsize, ShaderID());
+
+	r_shader_desc.specialization_constants.resize(binary_data.specialization_constants_count);
+	shader_info_in.specialization_constants.resize(binary_data.specialization_constants_count);
+	for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
+		const ShaderBinary::SpecializationConstant &src_sc = *(reinterpret_cast<const ShaderBinary::SpecializationConstant *>(binptr + read_offset));
+		ShaderSpecializationConstant sc;
+		sc.type = PipelineSpecializationConstantType(src_sc.type);
+		sc.constant_id = src_sc.constant_id;
+		sc.int_value = src_sc.int_value;
+		sc.stages = src_sc.stage_flags;
+		r_shader_desc.specialization_constants.write[i] = sc;
+
+		ShaderInfo::SpecializationConstant ssc;
+		ssc.constant_id = src_sc.constant_id;
+		ssc.int_value = src_sc.int_value;
+		memcpy(ssc.stages_bit_offsets, src_sc.stages_bit_offsets, sizeof(ssc.stages_bit_offsets));
+		shader_info_in.specialization_constants[i] = ssc;
+
+		read_offset += sizeof(ShaderBinary::SpecializationConstant);
+	}
+	shader_info_in.spirv_specialization_constants_ids_mask = binary_data.spirv_specialization_constants_ids_mask;
+
+	for (uint32_t i = 0; i < binary_data.stage_count; i++) {
+		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, ShaderID());
+		uint32_t stage = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		uint32_t dxil_size = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		uint32_t zstd_size = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+
+		// Decompress.
+		Vector<uint8_t> dxil;
+		dxil.resize(dxil_size);
+		int dec_dxil_size = Compression::decompress(dxil.ptrw(), dxil.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
+		ERR_FAIL_COND_V(dec_dxil_size != (int32_t)dxil_size, ShaderID());
+		shader_info_in.stages_bytecode[ShaderStage(stage)] = dxil;
+
+		if (zstd_size % 4 != 0) {
+			zstd_size += 4 - (zstd_size % 4);
+		}
+
+		ERR_FAIL_COND_V(read_offset + zstd_size > binsize, ShaderID());
+
+		read_offset += zstd_size;
+	}
+
+	const uint8_t *root_sig_data_ptr = binptr + read_offset;
+
+	HRESULT res = D3D12CreateRootSignatureDeserializer(root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(shader_info_in.root_signature_deserializer.GetAddressOf()));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "D3D12CreateRootSignatureDeserializer failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	read_offset += binary_data.root_signature_len;
+
+	ERR_FAIL_COND_V(read_offset != binsize, ShaderID());
+
+	ComPtr<ID3D12RootSignature> root_signature;
+	res = device->CreateRootSignature(0, root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(shader_info_in.root_signature.GetAddressOf()));
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "CreateRootSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	shader_info_in.root_signature_desc = shader_info_in.root_signature_deserializer->GetRootSignatureDesc();
+	shader_info_in.root_signature_crc = binary_data.root_signature_crc;
+
+	// Bookkeep.
+
+	ShaderInfo *shader_info_ptr = VersatileResource::allocate<ShaderInfo>(resources_allocator);
+	*shader_info_ptr = shader_info_in;
+	return ShaderID(shader_info_ptr);
+}
+
+uint32_t RenderingDeviceDriverD3D12::shader_get_layout_hash(ShaderID p_shader) {
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+	return shader_info_in->root_signature_crc;
+}
+
+void RenderingDeviceDriverD3D12::shader_free(ShaderID p_shader) {
+	ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;
+	VersatileResource::free(resources_allocator, shader_info_in);
+}
+
+/*********************/
+/**** UNIFORM SET ****/
+/*********************/
+
+static void _add_descriptor_count_for_uniform(RenderingDevice::UniformType p_type, uint32_t p_binding_length, bool p_dobule_srv_uav_ambiguous, uint32_t &r_num_resources, uint32_t &r_num_samplers, bool &r_srv_uav_ambiguity) {
+	r_srv_uav_ambiguity = false;
+
+	// Some resource types can be SRV or UAV, depending on what NIR-DXIL decided for a specific shader variant.
+	// The goal is to generate both SRV and UAV for the descriptor sets' heaps and copy only the relevant one
+	// to the frame descriptor heap at binding time.
+	// [[SRV_UAV_AMBIGUITY]]
+
+	switch (p_type) {
+		case RenderingDevice::UNIFORM_TYPE_SAMPLER: {
+			r_num_samplers += p_binding_length;
+		} break;
+		case RenderingDevice::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE:
+		case RenderingDevice::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
+			r_num_resources += p_binding_length;
+			r_num_samplers += p_binding_length;
+		} break;
+		case RenderingDevice::UNIFORM_TYPE_UNIFORM_BUFFER: {
+			r_num_resources += 1;
+		} break;
+		case RenderingDevice::UNIFORM_TYPE_STORAGE_BUFFER: {
+			r_num_resources += p_dobule_srv_uav_ambiguous ? 2 : 1;
+			r_srv_uav_ambiguity = true;
+		} break;
+		case RenderingDevice::UNIFORM_TYPE_IMAGE: {
+			r_num_resources += p_binding_length * (p_dobule_srv_uav_ambiguous ? 2 : 1);
+			r_srv_uav_ambiguity = true;
+		} break;
+		default: {
+			r_num_resources += p_binding_length;
+		}
+	}
+}
+
+RDD::UniformSetID RenderingDeviceDriverD3D12::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) {
+	// Pre-bookkeep.
+	UniformSetInfo *uniform_set_info = VersatileResource::allocate<UniformSetInfo>(resources_allocator);
+
+	// Do a first pass to count resources and samplers.
+	uint32_t num_resource_descs = 0;
+	uint32_t num_sampler_descs = 0;
+	for (uint32_t i = 0; i < p_uniforms.size(); i++) {
+		const BoundUniform &uniform = p_uniforms[i];
+
+		// Since the uniform set may be created for a shader different than the one that will be actually bound,
+		// which may have a different set of uniforms optimized out, the stages mask we can check now is not reliable.
+		// Therefore, we can't make any assumptions here about descriptors that we may not need to create,
+		// pixel or vertex-only shader resource states, etc.
+
+		bool srv_uav_ambiguity = false;
+		uint32_t binding_length = uniform.ids.size();
+		if (uniform.type == UNIFORM_TYPE_SAMPLER_WITH_TEXTURE || uniform.type == UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER) {
+			binding_length /= 2;
+		}
+		_add_descriptor_count_for_uniform(uniform.type, binding_length, true, num_resource_descs, num_sampler_descs, srv_uav_ambiguity);
+	}
+#ifdef DEV_ENABLED
+	uniform_set_info->resources_desc_info.reserve(num_resource_descs);
+#endif
+
+	if (num_resource_descs) {
+		Error err = uniform_set_info->desc_heaps.resources.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, num_resource_descs, false);
+		if (err) {
+			VersatileResource::free(resources_allocator, uniform_set_info);
+			ERR_FAIL_V(UniformSetID());
+		}
+	}
+	if (num_sampler_descs) {
+		Error err = uniform_set_info->desc_heaps.samplers.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_sampler_descs, false);
+		if (err) {
+			VersatileResource::free(resources_allocator, uniform_set_info);
+			ERR_FAIL_V(UniformSetID());
+		}
+	}
+	struct {
+		DescriptorsHeap::Walker resources;
+		DescriptorsHeap::Walker samplers;
+	} desc_heap_walkers;
+	desc_heap_walkers.resources = uniform_set_info->desc_heaps.resources.make_walker();
+	desc_heap_walkers.samplers = uniform_set_info->desc_heaps.samplers.make_walker();
+
+	struct NeededState {
+		bool is_buffer = false;
+		uint64_t shader_uniform_idx_mask = 0;
+		D3D12_RESOURCE_STATES states = {};
+	};
+	HashMap<ResourceInfo *, NeededState> resource_states;
+
+	for (uint32_t i = 0; i < p_uniforms.size(); i++) {
+		const BoundUniform &uniform = p_uniforms[i];
+
+#ifdef DEV_ENABLED
+		const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+		const ShaderInfo::UniformBindingInfo &shader_uniform = shader_info_in->sets[p_set_index].bindings[i];
+		bool is_compute = shader_info_in->stages_bytecode.has(SHADER_STAGE_COMPUTE);
+		DEV_ASSERT(!(is_compute && (shader_uniform.stages & (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT))));
+		DEV_ASSERT(!(!is_compute && (shader_uniform.stages & SHADER_STAGE_COMPUTE_BIT)));
+#endif
+
+		switch (uniform.type) {
+			case UNIFORM_TYPE_SAMPLER: {
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];
+					device->CreateSampler(&sampler_desc, desc_heap_walkers.samplers.get_curr_cpu_handle());
+					desc_heap_walkers.samplers.advance();
+				}
+			} break;
+			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
+				for (uint32_t j = 0; j < uniform.ids.size(); j += 2) {
+					const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j + 1].id;
+
+					device->CreateSampler(&sampler_desc, desc_heap_walkers.samplers.get_curr_cpu_handle());
+					desc_heap_walkers.samplers.advance();
+					device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_info->view_descs.srv.ViewDimension });
+#endif
+					desc_heap_walkers.resources.advance();
+
+					NeededState &ns = resource_states[texture_info];
+					ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+					ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
+				}
+			} break;
+			case UNIFORM_TYPE_TEXTURE: {
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
+					device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_info->view_descs.srv.ViewDimension });
+#endif
+					desc_heap_walkers.resources.advance();
+
+					NeededState &ns = resource_states[texture_info];
+					ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+					ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
+				}
+			} break;
+			case UNIFORM_TYPE_IMAGE: {
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
+
+					NeededState &ns = resource_states[texture_info];
+					ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+					ns.states |= (D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+				}
+
+				// SRVs first. [[SRV_UAV_AMBIGUITY]]
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
+
+					device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_info->view_descs.srv.ViewDimension });
+#endif
+					desc_heap_walkers.resources.advance();
+				}
+
+				// UAVs then. [[SRV_UAV_AMBIGUITY]]
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
+
+					device->CreateUnorderedAccessView(texture_info->resource, nullptr, &texture_info->view_descs.uav, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_UAV, {} });
+#endif
+					desc_heap_walkers.resources.advance();
+				}
+			} break;
+			case UNIFORM_TYPE_TEXTURE_BUFFER:
+			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
+				CRASH_NOW_MSG("Unimplemented!");
+			} break;
+			case UNIFORM_TYPE_IMAGE_BUFFER: {
+				CRASH_NOW_MSG("Unimplemented!");
+			} break;
+			case UNIFORM_TYPE_UNIFORM_BUFFER: {
+				BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;
+
+				D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {};
+				cbv_desc.BufferLocation = buf_info->resource->GetGPUVirtualAddress();
+				cbv_desc.SizeInBytes = STEPIFY(buf_info->size, 256);
+				device->CreateConstantBufferView(&cbv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
+				desc_heap_walkers.resources.advance();
+#ifdef DEV_ENABLED
+				uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_CBV, {} });
+#endif
+
+				NeededState &ns = resource_states[buf_info];
+				ns.is_buffer = true;
+				ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+				ns.states |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+			} break;
+			case UNIFORM_TYPE_STORAGE_BUFFER: {
+				BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;
+
+				// SRV first. [[SRV_UAV_AMBIGUITY]]
+				{
+					D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+					srv_desc.Format = DXGI_FORMAT_R32_TYPELESS;
+					srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
+					srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+					srv_desc.Buffer.FirstElement = 0;
+					srv_desc.Buffer.NumElements = (buf_info->size + 3) / 4;
+					srv_desc.Buffer.StructureByteStride = 0;
+					srv_desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
+					device->CreateShaderResourceView(buf_info->resource, &srv_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, srv_desc.ViewDimension });
+#endif
+					desc_heap_walkers.resources.advance();
+				}
+
+				// UAV then. [[SRV_UAV_AMBIGUITY]]
+				{
+					if (buf_info->flags.usable_as_uav) {
+						D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
+						uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
+						uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
+						uav_desc.Buffer.FirstElement = 0;
+						uav_desc.Buffer.NumElements = (buf_info->size + 3) / 4;
+						uav_desc.Buffer.StructureByteStride = 0;
+						uav_desc.Buffer.CounterOffsetInBytes = 0;
+						uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
+						device->CreateUnorderedAccessView(buf_info->resource, nullptr, &uav_desc, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+						uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_UAV, {} });
+#endif
+					} else {
+						// If can't transition to UAV, leave this one empty since it won't be
+						// used, and trying to create an UAV view would trigger a validation error.
+					}
+
+					desc_heap_walkers.resources.advance();
+				}
+
+				NeededState &ns = resource_states[buf_info];
+				ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+				ns.is_buffer = true;
+				ns.states |= (D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+			} break;
+			case UNIFORM_TYPE_INPUT_ATTACHMENT: {
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
+
+					device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, desc_heap_walkers.resources.get_curr_cpu_handle());
+#ifdef DEV_ENABLED
+					uniform_set_info->resources_desc_info.push_back({ D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_info->view_descs.srv.ViewDimension });
+#endif
+					desc_heap_walkers.resources.advance();
+
+					NeededState &ns = resource_states[texture_info];
+					ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
+					ns.states |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+				}
+			} break;
+			default: {
+				DEV_ASSERT(false);
+			}
+		}
+	}
+
+	DEV_ASSERT(desc_heap_walkers.resources.is_at_eof());
+	DEV_ASSERT(desc_heap_walkers.samplers.is_at_eof());
+
+	{
+		uniform_set_info->resource_states.reserve(resource_states.size());
+		uint32_t i = 0;
+		for (const KeyValue<ResourceInfo *, NeededState> &E : resource_states) {
+			UniformSetInfo::StateRequirement sr;
+			sr.resource = E.key;
+			sr.is_buffer = E.value.is_buffer;
+			sr.states = E.value.states;
+			sr.shader_uniform_idx_mask = E.value.shader_uniform_idx_mask;
+			uniform_set_info->resource_states.push_back(sr);
+			i++;
+		}
+	}
+
+	return UniformSetID(uniform_set_info);
+}
+
+void RenderingDeviceDriverD3D12::uniform_set_free(UniformSetID p_uniform_set) {
+	UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_set.id;
+	VersatileResource::free(resources_allocator, uniform_set_info);
+}
+
+// ----- COMMANDS -----
+
+void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+	const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id;
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+	const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index];
+
+	for (const UniformSetInfo::StateRequirement &sr : uniform_set_info->resource_states) {
+#ifdef DEV_ENABLED
+		{
+			uint32_t stages = 0;
+			D3D12_RESOURCE_STATES wanted_state = {};
+			bool writable = false;
+			// Doing the full loop for debugging since the real one below may break early,
+			// but we want an exhaustive check
+			uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
+			for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
+				uint64_t bit_mask = ((uint64_t)1 << bit);
+				if (likely((inv_uniforms_mask & bit_mask))) {
+					continue;
+				}
+				inv_uniforms_mask |= bit_mask;
+
+				const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];
+				if (unlikely(!binding.stages)) {
+					continue;
+				}
+
+				D3D12_RESOURCE_STATES required_states = sr.states;
+
+				// Resolve a case of SRV/UAV ambiguity now. [[SRV_UAV_AMBIGUITY]]
+				if ((required_states & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE) && (required_states & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
+					if (binding.res_class == RES_CLASS_SRV) {
+						required_states &= ~D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					} else {
+						required_states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					}
+				}
+
+				if (stages) { // Second occurrence at least?
+					CRASH_COND_MSG(binding.writable != writable, "A resource is used in the same uniform set both as R/O and R/W. That's not supported and shouldn't happen.");
+					CRASH_COND_MSG(required_states != wanted_state, "A resource is used in the same uniform set with different resource states. The code needs to be enhanced to support that.");
+				} else {
+					wanted_state = required_states;
+					stages |= binding.stages;
+					writable = binding.writable;
+				}
+
+				DEV_ASSERT((wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == (bool)(wanted_state & D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
+
+				if (wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS || wanted_state == D3D12_RESOURCE_STATE_RENDER_TARGET) {
+					if (!sr.is_buffer) {
+						TextureInfo *tex_info = (TextureInfo *)sr.resource;
+						CRASH_COND_MSG(tex_info->resource != tex_info->main_texture, "The texture format used for UAV or RTV must be the main one.");
+					}
+				}
+			}
+		}
+#endif
+
+		// We may have assumed D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE for a resource,
+		// because at uniform set creation time we couldn't know for sure which stages
+		// it would be used in (due to the fact that a set can be created against a different,
+		// albeit compatible, shader, which may make a different usage in the end).
+		// However, now we know and can exclude up to one unneeded states.
+
+		// TODO: If subresources involved already in the needed states, or scheduled for it,
+		// maybe it's more optimal not to do anything here
+
+		uint32_t stages = 0;
+		D3D12_RESOURCE_STATES wanted_state = {};
+		uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
+		for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
+			uint64_t bit_mask = ((uint64_t)1 << bit);
+			if (likely((inv_uniforms_mask & bit_mask))) {
+				continue;
+			}
+			inv_uniforms_mask |= bit_mask;
+
+			const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];
+			if (unlikely(!binding.stages)) {
+				continue;
+			}
+
+			if (!stages) {
+				D3D12_RESOURCE_STATES required_states = sr.states;
+
+				// Resolve a case of SRV/UAV ambiguity now. [[SRV_UAV_AMBIGUITY]]
+				if ((required_states & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE) && (required_states & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)) {
+					if (binding.res_class == RES_CLASS_SRV) {
+						required_states &= ~D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					} else {
+						required_states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+					}
+				}
+
+				wanted_state = required_states;
+
+				if (!(wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
+					// By now, we already know the resource is used, and with no PS/NON_PS disjuntive; no need to check further.
+					break;
+				}
+			}
+
+			stages |= binding.stages;
+
+			if (stages == (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT) || stages == SHADER_STAGE_COMPUTE_BIT) {
+				// By now, we already know the resource is used, and as both PS/NON_PS; no need to check further.
+				break;
+			}
+		}
+
+		if (likely(wanted_state)) {
+			if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
+				if (stages == SHADER_STAGE_VERTEX_BIT || stages == SHADER_STAGE_COMPUTE_BIT) {
+					D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+					wanted_state &= ~unneeded_states;
+				} else if (stages == SHADER_STAGE_FRAGMENT_BIT) {
+					D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+					wanted_state &= ~unneeded_states;
+				}
+			}
+
+			if (likely(wanted_state)) {
+				if (sr.is_buffer) {
+					_resource_transition_batch(sr.resource, 0, 1, wanted_state);
+				} else {
+					TextureInfo *tex_info = (TextureInfo *)sr.resource;
+					uint32_t planes = 1;
+					if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+						planes = format_get_plane_count(tex_info->format);
+					}
+					for (uint32_t i = 0; i < tex_info->layers; i++) {
+						for (uint32_t j = 0; j < tex_info->mipmaps; j++) {
+							uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize());
+							_resource_transition_batch(tex_info, subresource, planes, wanted_state, tex_info->main_texture);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (p_set_index == shader_info_in->sets.size() - 1) {
+		const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	}
+}
+
+void RenderingDeviceDriverD3D12::_command_bind_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index, bool p_for_compute) {
+	if (!unlikely(segment_begun)) {
+		// Support out-of-frame rendering, like the boot splash screen.
+		begin_segment(p_cmd_buffer, frame_idx, frames_drawn);
+	}
+
+	UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_set.id;
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+	const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index];
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+
+	using SetRootDescriptorTableFn = void (STDMETHODCALLTYPE ID3D12GraphicsCommandList::*)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE);
+	SetRootDescriptorTableFn set_root_desc_table_fn = p_for_compute ? &ID3D12GraphicsCommandList::SetComputeRootDescriptorTable : &ID3D12GraphicsCommandList1::SetGraphicsRootDescriptorTable;
+
+	// If this set's descriptors have already been set for the current execution and a compatible root signature, reuse!
+	uint32_t root_sig_crc = p_for_compute ? cmd_buf_info->compute_root_signature_crc : cmd_buf_info->graphics_root_signature_crc;
+	UniformSetInfo::RecentBind *last_bind = nullptr;
+	for (int i = 0; i < (int)ARRAY_SIZE(uniform_set_info->recent_binds); i++) {
+		if (uniform_set_info->recent_binds[i].segment_serial == frames[frame_idx].segment_serial) {
+			if (uniform_set_info->recent_binds[i].root_signature_crc == root_sig_crc) {
+				for (const RootDescriptorTable &table : uniform_set_info->recent_binds[i].root_tables.resources) {
+					(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(table.root_param_idx, table.start_gpu_handle);
+				}
+				for (const RootDescriptorTable &table : uniform_set_info->recent_binds[i].root_tables.samplers) {
+					(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(table.root_param_idx, table.start_gpu_handle);
+				}
+#ifdef DEV_ENABLED
+				uniform_set_info->recent_binds[i].uses++;
+				frames[frame_idx].uniform_set_reused++;
+#endif
+				return;
+			} else {
+				if (!last_bind || uniform_set_info->recent_binds[i].uses < last_bind->uses) {
+					// Prefer this one since it's been used less or we still haven't a better option.
+					last_bind = &uniform_set_info->recent_binds[i];
+				}
+			}
+		} else {
+			// Prefer this one since it's unused.
+			last_bind = &uniform_set_info->recent_binds[i];
+			last_bind->uses = 0;
+		}
+	}
+
+	struct {
+		DescriptorsHeap::Walker *resources = nullptr;
+		DescriptorsHeap::Walker *samplers = nullptr;
+	} frame_heap_walkers;
+	frame_heap_walkers.resources = &frames[frame_idx].desc_heap_walkers.resources;
+	frame_heap_walkers.samplers = &frames[frame_idx].desc_heap_walkers.samplers;
+
+	struct {
+		DescriptorsHeap::Walker resources;
+		DescriptorsHeap::Walker samplers;
+	} set_heap_walkers;
+	set_heap_walkers.resources = uniform_set_info->desc_heaps.resources.make_walker();
+	set_heap_walkers.samplers = uniform_set_info->desc_heaps.samplers.make_walker();
+
+#ifdef DEV_ENABLED
+	// Whether we have stages where the uniform is actually used should match
+	// whether we have any root signature locations for it.
+	for (uint32_t i = 0; i < shader_set.bindings.size(); i++) {
+		bool has_rs_locations = false;
+		if (shader_set.bindings[i].root_sig_locations.resource.root_param_idx != UINT32_MAX ||
+				shader_set.bindings[i].root_sig_locations.sampler.root_param_idx != UINT32_MAX) {
+			has_rs_locations = true;
+			break;
+		}
+
+		bool has_stages = shader_set.bindings[i].stages;
+
+		DEV_ASSERT(has_rs_locations == has_stages);
+	}
+#endif
+
+	last_bind->root_tables.resources.reserve(shader_set.num_root_params.resources);
+	last_bind->root_tables.resources.clear();
+	last_bind->root_tables.samplers.reserve(shader_set.num_root_params.samplers);
+	last_bind->root_tables.samplers.clear();
+	last_bind->uses++;
+
+	struct {
+		RootDescriptorTable *resources = nullptr;
+		RootDescriptorTable *samplers = nullptr;
+	} tables;
+	for (uint32_t i = 0; i < shader_set.bindings.size(); i++) {
+		const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[i];
+
+		uint32_t num_resource_descs = 0;
+		uint32_t num_sampler_descs = 0;
+		bool srv_uav_ambiguity = false;
+		_add_descriptor_count_for_uniform(binding.type, binding.length, false, num_resource_descs, num_sampler_descs, srv_uav_ambiguity);
+
+		bool resource_used = false;
+		if (shader_set.bindings[i].stages) {
+			{
+				const ShaderInfo::UniformBindingInfo::RootSignatureLocation &rs_loc_resource = shader_set.bindings[i].root_sig_locations.resource;
+				if (rs_loc_resource.root_param_idx != UINT32_MAX) { // Location used?
+					DEV_ASSERT(num_resource_descs);
+					DEV_ASSERT(!(srv_uav_ambiguity && (shader_set.bindings[i].res_class != RES_CLASS_SRV && shader_set.bindings[i].res_class != RES_CLASS_UAV))); // [[SRV_UAV_AMBIGUITY]]
+
+					bool must_flush_table = tables.resources && rs_loc_resource.root_param_idx != tables.resources->root_param_idx;
+					if (must_flush_table) {
+						// Check the root signature data has been filled ordered.
+						DEV_ASSERT(rs_loc_resource.root_param_idx > tables.resources->root_param_idx);
+
+						(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(tables.resources->root_param_idx, tables.resources->start_gpu_handle);
+						tables.resources = nullptr;
+					}
+
+					if (unlikely(frame_heap_walkers.resources->get_free_handles() < num_resource_descs)) {
+						if (!frames[frame_idx].desc_heaps_exhausted_reported.resources) {
+							frames[frame_idx].desc_heaps_exhausted_reported.resources = true;
+							ERR_FAIL_MSG("Cannot bind uniform set because there's no enough room in current frame's RESOURCES descriptor heap.\n"
+										 "Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
+						} else {
+							return;
+						}
+					}
+
+					if (!tables.resources) {
+						DEV_ASSERT(last_bind->root_tables.resources.size() < last_bind->root_tables.resources.get_capacity());
+						last_bind->root_tables.resources.resize(last_bind->root_tables.resources.size() + 1);
+						tables.resources = &last_bind->root_tables.resources[last_bind->root_tables.resources.size() - 1];
+						tables.resources->root_param_idx = rs_loc_resource.root_param_idx;
+						tables.resources->start_gpu_handle = frame_heap_walkers.resources->get_curr_gpu_handle();
+					}
+
+					// If there is ambiguity and it didn't clarify as SRVs, skip them, which come first. [[SRV_UAV_AMBIGUITY]]
+					if (srv_uav_ambiguity && shader_set.bindings[i].res_class != RES_CLASS_SRV) {
+						set_heap_walkers.resources.advance(num_resource_descs);
+					}
+
+					// TODO: Batch to avoid multiple calls where possible (in any case, flush before setting root descriptor tables, or even batch that as well).
+					device->CopyDescriptorsSimple(
+							num_resource_descs,
+							frame_heap_walkers.resources->get_curr_cpu_handle(),
+							set_heap_walkers.resources.get_curr_cpu_handle(),
+							D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+					frame_heap_walkers.resources->advance(num_resource_descs);
+
+					// If there is ambiguity and it didn't clarify as UAVs, skip them, which come later. [[SRV_UAV_AMBIGUITY]]
+					if (srv_uav_ambiguity && shader_set.bindings[i].res_class != RES_CLASS_UAV) {
+						set_heap_walkers.resources.advance(num_resource_descs);
+					}
+
+					resource_used = true;
+				}
+			}
+
+			{
+				const ShaderInfo::UniformBindingInfo::RootSignatureLocation &rs_loc_sampler = shader_set.bindings[i].root_sig_locations.sampler;
+				if (rs_loc_sampler.root_param_idx != UINT32_MAX) { // Location used?
+					DEV_ASSERT(num_sampler_descs);
+					DEV_ASSERT(!srv_uav_ambiguity); // [[SRV_UAV_AMBIGUITY]]
+
+					bool must_flush_table = tables.samplers && rs_loc_sampler.root_param_idx != tables.samplers->root_param_idx;
+					if (must_flush_table) {
+						// Check the root signature data has been filled ordered.
+						DEV_ASSERT(rs_loc_sampler.root_param_idx > tables.samplers->root_param_idx);
+
+						(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(tables.samplers->root_param_idx, tables.samplers->start_gpu_handle);
+						tables.samplers = nullptr;
+					}
+
+					if (unlikely(frame_heap_walkers.samplers->get_free_handles() < num_sampler_descs)) {
+						if (!frames[frame_idx].desc_heaps_exhausted_reported.samplers) {
+							frames[frame_idx].desc_heaps_exhausted_reported.samplers = true;
+							ERR_FAIL_MSG("Cannot bind uniform set because there's no enough room in current frame's SAMPLERS descriptors heap.\n"
+										 "Please increase the value of the rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame project setting.");
+						} else {
+							return;
+						}
+					}
+
+					if (!tables.samplers) {
+						DEV_ASSERT(last_bind->root_tables.samplers.size() < last_bind->root_tables.samplers.get_capacity());
+						last_bind->root_tables.samplers.resize(last_bind->root_tables.samplers.size() + 1);
+						tables.samplers = &last_bind->root_tables.samplers[last_bind->root_tables.samplers.size() - 1];
+						tables.samplers->root_param_idx = rs_loc_sampler.root_param_idx;
+						tables.samplers->start_gpu_handle = frame_heap_walkers.samplers->get_curr_gpu_handle();
+					}
+
+					// TODO: Batch to avoid multiple calls where possible (in any case, flush before setting root descriptor tables, or even batch that as well).
+					device->CopyDescriptorsSimple(
+							num_sampler_descs,
+							frame_heap_walkers.samplers->get_curr_cpu_handle(),
+							set_heap_walkers.samplers.get_curr_cpu_handle(),
+							D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+					frame_heap_walkers.samplers->advance(num_sampler_descs);
+				}
+			}
+		}
+
+		// Uniform set descriptor heaps are always full (descriptors are created for every uniform in them) despite
+		// the shader variant a given set is created upon may not need all of them due to DXC optimizations.
+		// Therefore, at this point we have to advance through the descriptor set descriptor's heap unconditionally.
+
+		set_heap_walkers.resources.advance(num_resource_descs);
+		if (srv_uav_ambiguity) {
+			DEV_ASSERT(num_resource_descs);
+			if (!resource_used) {
+				set_heap_walkers.resources.advance(num_resource_descs); // Additional skip, since both SRVs and UAVs have to be bypassed.
+			}
+		}
+
+		set_heap_walkers.samplers.advance(num_sampler_descs);
+	}
+
+	DEV_ASSERT(set_heap_walkers.resources.is_at_eof());
+	DEV_ASSERT(set_heap_walkers.samplers.is_at_eof());
+
+	{
+		bool must_flush_table = tables.resources;
+		if (must_flush_table) {
+			(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(tables.resources->root_param_idx, tables.resources->start_gpu_handle);
+		}
+	}
+	{
+		bool must_flush_table = tables.samplers;
+		if (must_flush_table) {
+			(cmd_buf_info->cmd_list.Get()->*set_root_desc_table_fn)(tables.samplers->root_param_idx, tables.samplers->start_gpu_handle);
+		}
+	}
+
+	last_bind->root_signature_crc = root_sig_crc;
+	last_bind->segment_serial = frames[frame_idx].segment_serial;
+}
+
+/******************/
+/**** TRANSFER ****/
+/******************/
+
+void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
+
+	if (frames[frame_idx].desc_heap_walkers.resources.is_at_eof()) {
+		if (!frames[frame_idx].desc_heaps_exhausted_reported.resources) {
+			frames[frame_idx].desc_heaps_exhausted_reported.resources = true;
+			ERR_FAIL_MSG(
+					"Cannot clear buffer because there's no enough room in current frame's RESOURCE descriptors heap.\n"
+					"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
+		} else {
+			return;
+		}
+	}
+	if (frames[frame_idx].desc_heap_walkers.aux.is_at_eof()) {
+		if (!frames[frame_idx].desc_heaps_exhausted_reported.aux) {
+			frames[frame_idx].desc_heaps_exhausted_reported.aux = true;
+			ERR_FAIL_MSG(
+					"Cannot clear buffer because there's no enough room in current frame's AUX descriptors heap.\n"
+					"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
+		} else {
+			return;
+		}
+	}
+
+	_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
+	uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
+	uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
+	uav_desc.Buffer.FirstElement = 0;
+	uav_desc.Buffer.NumElements = (buf_info->size + 3) / 4;
+	uav_desc.Buffer.StructureByteStride = 0;
+	uav_desc.Buffer.CounterOffsetInBytes = 0;
+	uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
+	device->CreateUnorderedAccessView(
+			buf_info->resource,
+			nullptr,
+			&uav_desc,
+			frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle());
+
+	device->CopyDescriptorsSimple(
+			1,
+			frames[frame_idx].desc_heap_walkers.resources.get_curr_cpu_handle(),
+			frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(),
+			D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+	static const UINT values[4] = {};
+	cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(
+			frames[frame_idx].desc_heap_walkers.resources.get_curr_gpu_handle(),
+			frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(),
+			buf_info->resource,
+			values,
+			0,
+			nullptr);
+
+	frames[frame_idx].desc_heap_walkers.resources.advance();
+	frames[frame_idx].desc_heap_walkers.aux.advance();
+}
+
+void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id;
+	BufferInfo *dst_buf_info = (BufferInfo *)p_dst_buffer.id;
+
+	_resource_transition_batch(src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
+	_resource_transition_batch(dst_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		cmd_buf_info->cmd_list->CopyBufferRegion(dst_buf_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size);
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
+	TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
+
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		UINT src_subresource = D3D12CalcSubresource(
+				p_regions[i].src_subresources.mipmap,
+				p_regions[i].src_subresources.base_layer,
+				_compute_plane_slice(src_tex_info->format, p_regions[i].src_subresources.aspect),
+				src_tex_info->desc.MipLevels,
+				src_tex_info->desc.ArraySize());
+		_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
+
+		UINT dst_subresource = D3D12CalcSubresource(
+				p_regions[i].dst_subresources.mipmap,
+				p_regions[i].dst_subresources.base_layer,
+				_compute_plane_slice(dst_tex_info->format, p_regions[i].dst_subresources.aspect),
+				dst_tex_info->desc.MipLevels,
+				dst_tex_info->desc.ArraySize());
+		_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
+
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+		CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex_info->resource, src_subresource);
+		CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex_info->resource, dst_subresource);
+
+		CD3DX12_BOX src_box(
+				p_regions[i].src_offset.x,
+				p_regions[i].src_offset.y,
+				p_regions[i].src_offset.z,
+				p_regions[i].src_offset.x + p_regions[i].size.x,
+				p_regions[i].src_offset.y + p_regions[i].size.y,
+				p_regions[i].src_offset.z + p_regions[i].size.z);
+
+		cmd_buf_info->cmd_list->CopyTextureRegion(
+				&dst_location,
+				p_regions[i].dst_offset.x,
+				p_regions[i].dst_offset.y,
+				p_regions[i].dst_offset.z,
+				&src_location,
+				&src_box);
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
+	TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
+
+	UINT src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
+	_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
+
+	UINT dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
+	_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
+
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	cmd_buf_info->cmd_list->ResolveSubresource(dst_tex_info->resource, dst_subresource, src_tex_info->resource, src_subresource, RD_TO_D3D12_FORMAT[src_tex_info->format].general_format);
+}
+
+void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+
+	ID3D12Resource *res_to_clear = tex_info->main_texture ? tex_info->main_texture : tex_info->resource;
+	if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+		// Clear via RTV.
+
+		if (frames[frame_idx].desc_heap_walkers.rtv.is_at_eof()) {
+			if (!frames[frame_idx].desc_heaps_exhausted_reported.rtv) {
+				frames[frame_idx].desc_heaps_exhausted_reported.rtv = true;
+				ERR_FAIL_MSG(
+						"Cannot clear texture because there's no enough room in current frame's RENDER TARGET descriptors heap.\n"
+						"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
+			} else {
+				return;
+			}
+		}
+
+		D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap, p_subresources.base_layer, p_subresources.layer_count, false);
+		rtv_desc.Format = tex_info->aliasing_hack.main_uav_desc.Format;
+
+		for (uint32_t i = 0; i < p_subresources.layer_count; i++) {
+			for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {
+				UINT subresource = D3D12CalcSubresource(
+						p_subresources.base_mipmap + j,
+						p_subresources.base_layer + i,
+						0,
+						tex_info->desc.MipLevels,
+						tex_info->desc.ArraySize());
+				_resource_transition_batch(tex_info, subresource, 1, D3D12_RESOURCE_STATE_RENDER_TARGET, tex_info->main_texture);
+			}
+		}
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+		device->CreateRenderTargetView(
+				res_to_clear,
+				&rtv_desc,
+				frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle());
+		cmd_buf_info->cmd_list->ClearRenderTargetView(
+				frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle(),
+				p_color.components,
+				0,
+				nullptr);
+		frames[frame_idx].desc_heap_walkers.rtv.advance();
+	} else {
+		// Clear via UAV.
+
+		if (frames[frame_idx].desc_heap_walkers.resources.is_at_eof()) {
+			if (!frames[frame_idx].desc_heaps_exhausted_reported.resources) {
+				frames[frame_idx].desc_heaps_exhausted_reported.resources = true;
+				ERR_FAIL_MSG(
+						"Cannot clear texture because there's no enough room in current frame's RESOURCE descriptors heap.\n"
+						"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors_per_frame project setting.");
+			} else {
+				return;
+			}
+		}
+		if (frames[frame_idx].desc_heap_walkers.aux.is_at_eof()) {
+			if (!frames[frame_idx].desc_heaps_exhausted_reported.aux) {
+				frames[frame_idx].desc_heaps_exhausted_reported.aux = true;
+				ERR_FAIL_MSG(
+						"Cannot clear texture because there's no enough room in current frame's AUX descriptors heap.\n"
+						"Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
+			} else {
+				return;
+			}
+		}
+
+		for (uint32_t i = 0; i < p_subresources.layer_count; i++) {
+			for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {
+				UINT subresource = D3D12CalcSubresource(
+						p_subresources.base_mipmap + j,
+						p_subresources.base_layer + i,
+						0,
+						tex_info->desc.MipLevels,
+						tex_info->desc.ArraySize());
+				_resource_transition_batch(tex_info, subresource, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, tex_info->main_texture);
+			}
+		}
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+		device->CreateUnorderedAccessView(
+				res_to_clear,
+				nullptr,
+				&tex_info->aliasing_hack.main_uav_desc,
+				frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle());
+
+		device->CopyDescriptorsSimple(
+				1,
+				frames[frame_idx].desc_heap_walkers.resources.get_curr_cpu_handle(),
+				frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(),
+				D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+		UINT values[4] = {
+			(UINT)p_color.get_r8(),
+			(UINT)p_color.get_g8(),
+			(UINT)p_color.get_b8(),
+			(UINT)p_color.get_a8(),
+		};
+		cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(
+				frames[frame_idx].desc_heap_walkers.resources.get_curr_gpu_handle(),
+				frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(),
+				res_to_clear,
+				values,
+				0,
+				nullptr);
+
+		frames[frame_idx].desc_heap_walkers.resources.advance();
+		frames[frame_idx].desc_heap_walkers.aux.advance();
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	BufferInfo *buf_info = (BufferInfo *)p_src_buffer.id;
+	TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id;
+
+	if (buf_info->flags.is_for_upload) {
+		_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE, nullptr);
+	}
+
+	uint32_t pixel_size = get_image_format_pixel_size(tex_info->format);
+	uint32_t block_w = 0, block_h = 0;
+	get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);
+
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		uint32_t region_pitch = (p_regions[i].texture_region_size.x * pixel_size * block_w) >> get_compressed_image_format_pixel_rshift(tex_info->format);
+		region_pitch = STEPIFY(region_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+
+		D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = {};
+		src_footprint.Offset = p_regions[i].buffer_offset;
+		src_footprint.Footprint = CD3DX12_SUBRESOURCE_FOOTPRINT(
+				RD_TO_D3D12_FORMAT[tex_info->format].family,
+				STEPIFY(p_regions[i].texture_region_size.x, block_w),
+				STEPIFY(p_regions[i].texture_region_size.y, block_h),
+				p_regions[i].texture_region_size.z,
+				region_pitch);
+		CD3DX12_TEXTURE_COPY_LOCATION copy_src(buf_info->resource, src_footprint);
+
+		CD3DX12_BOX src_box(
+				0, 0, 0,
+				STEPIFY(p_regions[i].texture_region_size.x, block_w),
+				STEPIFY(p_regions[i].texture_region_size.y, block_h),
+				p_regions[i].texture_region_size.z);
+
+		for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
+			UINT dst_subresource = D3D12CalcSubresource(
+					p_regions[i].texture_subresources.mipmap,
+					p_regions[i].texture_subresources.base_layer + j,
+					_compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect),
+					tex_info->desc.MipLevels,
+					tex_info->desc.ArraySize());
+			CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource);
+
+			_resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST, tex_info->main_texture);
+		}
+
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+		for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
+			UINT dst_subresource = D3D12CalcSubresource(
+					p_regions[i].texture_subresources.mipmap,
+					p_regions[i].texture_subresources.base_layer + j,
+					_compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect),
+					tex_info->desc.MipLevels,
+					tex_info->desc.ArraySize());
+			CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource);
+
+			cmd_buf_info->cmd_list->CopyTextureRegion(
+					&copy_dst,
+					p_regions[i].texture_offset.x,
+					p_regions[i].texture_offset.y,
+					p_regions[i].texture_offset.z,
+					&copy_src,
+					&src_box);
+		}
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	TextureInfo *tex_info = (TextureInfo *)p_src_texture.id;
+	BufferInfo *buf_info = (BufferInfo *)p_dst_buffer.id;
+
+	_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST, nullptr);
+
+	uint32_t block_w = 0, block_h = 0;
+	get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);
+
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
+			UINT src_subresource = D3D12CalcSubresource(
+					p_regions[i].texture_subresources.mipmap,
+					p_regions[i].texture_subresources.base_layer + j,
+					_compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect),
+					tex_info->desc.MipLevels,
+					tex_info->desc.ArraySize());
+
+			_resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE, tex_info->main_texture);
+		}
+
+		_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+		for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
+			UINT src_subresource = D3D12CalcSubresource(
+					p_regions[i].texture_subresources.mipmap,
+					p_regions[i].texture_subresources.base_layer + j,
+					_compute_plane_slice(tex_info->format, p_regions[i].texture_subresources.aspect),
+					tex_info->desc.MipLevels,
+					tex_info->desc.ArraySize());
+
+			CD3DX12_TEXTURE_COPY_LOCATION copy_src(tex_info->resource, src_subresource);
+
+			uint32_t computed_d = MAX(1, tex_info->desc.DepthOrArraySize >> p_regions[i].texture_subresources.mipmap);
+			uint32_t image_size = get_image_format_required_size(
+					tex_info->format,
+					MAX(1u, tex_info->desc.Width >> p_regions[i].texture_subresources.mipmap),
+					MAX(1u, tex_info->desc.Height >> p_regions[i].texture_subresources.mipmap),
+					computed_d,
+					1);
+			uint32_t row_pitch = image_size / (p_regions[i].texture_region_size.y * computed_d) * block_h;
+			row_pitch = STEPIFY(row_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+
+			D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = {};
+			dst_footprint.Offset = p_regions[i].buffer_offset;
+			dst_footprint.Footprint.Width = STEPIFY(p_regions[i].texture_region_size.x, block_w);
+			dst_footprint.Footprint.Height = STEPIFY(p_regions[i].texture_region_size.y, block_h);
+			dst_footprint.Footprint.Depth = p_regions[i].texture_region_size.z;
+			dst_footprint.Footprint.RowPitch = row_pitch;
+			dst_footprint.Footprint.Format = RD_TO_D3D12_FORMAT[tex_info->format].family;
+
+			CD3DX12_TEXTURE_COPY_LOCATION copy_dst(buf_info->resource, dst_footprint);
+
+			cmd_buf_info->cmd_list->CopyTextureRegion(&copy_dst, 0, 0, 0, &copy_src, nullptr);
+		}
+	}
+}
+
+/******************/
+/**** PIPELINE ****/
+/******************/
+
+void RenderingDeviceDriverD3D12::pipeline_free(PipelineID p_pipeline) {
+	ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
+	pso->Release();
+	pipelines_shaders.erase(pso);
+	render_psos_extra_info.erase(pso);
+}
+
+// ----- BINDING -----
+
+void RenderingDeviceDriverD3D12::command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView<uint32_t> p_data) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+	if (!shader_info_in->dxil_push_constant_size) {
+		return;
+	}
+	if (shader_info_in->is_compute) {
+		cmd_buf_info->cmd_list->SetComputeRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
+	} else {
+		cmd_buf_info->cmd_list->SetGraphicsRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
+	}
+}
+
+// ----- CACHE -----
+
+bool RenderingDeviceDriverD3D12::pipeline_cache_create(const Vector<uint8_t> &p_data) {
+	WARN_PRINT("PSO caching is not implemented yet in the Direct3D 12 driver.");
+	return false;
+}
+
+void RenderingDeviceDriverD3D12::pipeline_cache_free() {
+	ERR_FAIL_MSG("Not implemented.");
+}
+
+size_t RenderingDeviceDriverD3D12::pipeline_cache_query_size() {
+	ERR_FAIL_V_MSG(0, "Not implemented.");
+}
+
+Vector<uint8_t> RenderingDeviceDriverD3D12::pipeline_cache_serialize() {
+	ERR_FAIL_V_MSG(Vector<uint8_t>(), "Not implemented.");
+}
+
+/*******************/
+/**** RENDERING ****/
+/*******************/
+
+// ----- SUBPASS -----
+
+RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) {
+	// Pre-bookkeep.
+	RenderPassInfo *pass_info = VersatileResource::allocate<RenderPassInfo>(resources_allocator);
+
+	pass_info->attachments.resize(p_attachments.size());
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		pass_info->attachments[i] = p_attachments[i];
+	}
+
+	pass_info->subpasses.resize(p_subpasses.size());
+	for (uint32_t i = 0; i < p_subpasses.size(); i++) {
+		pass_info->subpasses[i] = p_subpasses[i];
+	}
+
+	pass_info->view_count = p_view_count;
+
+	DXGI_FORMAT *formats = ALLOCA_ARRAY(DXGI_FORMAT, p_attachments.size());
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		const D3D12Format &format = RD_TO_D3D12_FORMAT[p_attachments[i].format];
+		if (format.dsv_format != DXGI_FORMAT_UNKNOWN) {
+			formats[i] = format.dsv_format;
+		} else {
+			formats[i] = format.general_format;
+		}
+	}
+	pass_info->max_supported_sample_count = _find_max_common_supported_sample_count(VectorView(formats, p_attachments.size()));
+
+	return RenderPassID(pass_info);
+}
+
+void RenderingDeviceDriverD3D12::render_pass_free(RenderPassID p_render_pass) {
+	RenderPassInfo *pass_info = (RenderPassInfo *)p_render_pass.id;
+	VersatileResource::free(resources_allocator, pass_info);
+}
+
+// ----- COMMANDS -----
+
+void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_attachment_clears) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
+	const FramebufferInfo *fb_info = (const FramebufferInfo *)p_framebuffer.id;
+
+	DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX);
+
+	auto _transition_subresources = [&](TextureInfo *p_texture_info, D3D12_RESOURCE_STATES p_states) {
+		uint32_t planes = 1;
+		if ((p_texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+			planes = format_get_plane_count(p_texture_info->format);
+		}
+		for (uint32_t i = 0; i < p_texture_info->layers; i++) {
+			for (uint32_t j = 0; j < p_texture_info->mipmaps; j++) {
+				uint32_t subresource = D3D12CalcSubresource(
+						p_texture_info->base_mip + j,
+						p_texture_info->base_layer + i,
+						0,
+						p_texture_info->desc.MipLevels,
+						p_texture_info->desc.ArraySize());
+				_resource_transition_batch(p_texture_info, subresource, planes, p_states, nullptr);
+			}
+		}
+	};
+
+	// This is empty if a screen framebuffer. Transition in that case happens in D3D12Context::prepare_buffers().
+	for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {
+		TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;
+		if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+			_transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET);
+		} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+			_transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE);
+		} else {
+			DEV_ASSERT(false);
+		}
+	}
+	if (fb_info->vrs_attachment) {
+		TextureInfo *tex_info = (TextureInfo *)fb_info->vrs_attachment.id;
+		_transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
+	}
+
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	cmd_buf_info->render_pass_state.region_rect = CD3DX12_RECT(
+			p_rect.position.x,
+			p_rect.position.y,
+			p_rect.position.x + p_rect.size.x,
+			p_rect.position.y + p_rect.size.y);
+	cmd_buf_info->render_pass_state.region_is_all = !(
+			cmd_buf_info->render_pass_state.region_rect.left == 0 &&
+			cmd_buf_info->render_pass_state.region_rect.top == 0 &&
+			cmd_buf_info->render_pass_state.region_rect.right == fb_info->size.x &&
+			cmd_buf_info->render_pass_state.region_rect.bottom == fb_info->size.y);
+
+	if (fb_info->is_screen) {
+		for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
+			if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_DONT_CARE) {
+				const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;
+				_discard_texture_subresources(tex_info, cmd_buf_info);
+			}
+		}
+	}
+
+	if (fb_info->vrs_attachment && context->get_vrs_capabilities().ss_image_supported) {
+		ComPtr<ID3D12GraphicsCommandList5> cmd_list_5;
+		cmd_buf_info->cmd_list->QueryInterface(cmd_list_5.GetAddressOf());
+		if (cmd_list_5) {
+			static const D3D12_SHADING_RATE_COMBINER COMBINERS[D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT] = {
+				D3D12_SHADING_RATE_COMBINER_PASSTHROUGH,
+				D3D12_SHADING_RATE_COMBINER_OVERRIDE,
+			};
+			cmd_list_5->RSSetShadingRate(D3D12_SHADING_RATE_1X1, COMBINERS);
+		}
+	}
+
+	cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;
+	cmd_buf_info->render_pass_state.fb_info = fb_info;
+	cmd_buf_info->render_pass_state.pass_info = pass_info;
+	command_next_render_subpass(p_cmd_buffer, p_cmd_buffer_type);
+
+	AttachmentClear *clears = ALLOCA_ARRAY(AttachmentClear, fb_info->is_screen ? 1 : pass_info->attachments.size());
+	Rect2i *clear_rects = ALLOCA_ARRAY(Rect2i, fb_info->is_screen ? 1 : pass_info->attachments.size());
+	uint32_t num_clears = 0;
+
+	if (fb_info->is_screen) {
+		clears[0].aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT);
+		clears[0].color_attachment = 0;
+		clears[0].value = p_attachment_clears[0];
+		clear_rects[0] = p_rect;
+		num_clears++;
+	} else {
+		for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
+			TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;
+			if (!tex_info) {
+				continue;
+			}
+
+			AttachmentClear clear;
+			if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+				if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) {
+					clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT);
+					clear.color_attachment = i;
+				}
+			} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
+				if (pass_info->attachments[i].stencil_load_op == ATTACHMENT_LOAD_OP_CLEAR) {
+					clear.aspect.set_flag(TEXTURE_ASPECT_DEPTH_BIT);
+				}
+			}
+			if (!clear.aspect.is_empty()) {
+				clear.value = p_attachment_clears[i];
+				clears[num_clears] = clear;
+				clear_rects[num_clears] = p_rect;
+				num_clears++;
+			}
+		}
+	}
+
+	if (num_clears) {
+		command_render_clear_attachments(p_cmd_buffer, VectorView(clears, num_clears), VectorView(clear_rects, num_clears));
+	}
+}
+
+void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+
+	DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
+
+	const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
+	const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
+	const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];
+
+	struct Resolve {
+		ID3D12Resource *src_res = nullptr;
+		uint32_t src_subres = 0;
+		ID3D12Resource *dst_res = nullptr;
+		uint32_t dst_subres = 0;
+		DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+	};
+	Resolve *resolves = ALLOCA_ARRAY(Resolve, subpass.resolve_references.size());
+	uint32_t num_resolves = 0;
+
+	for (uint32_t i = 0; i < subpass.resolve_references.size(); i++) {
+		uint32_t color_index = subpass.color_references[i].attachment;
+		uint32_t resolve_index = subpass.resolve_references[i].attachment;
+		DEV_ASSERT((color_index == AttachmentReference::UNUSED) == (resolve_index == AttachmentReference::UNUSED));
+		if (color_index == AttachmentReference::UNUSED || !fb_info->attachments[color_index]) {
+			continue;
+		}
+
+		TextureInfo *src_tex_info = (TextureInfo *)fb_info->attachments[color_index].id;
+		uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
+		_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
+
+		TextureInfo *dst_tex_info = (TextureInfo *)fb_info->attachments[resolve_index].id;
+		uint32_t dst_subresource = D3D12CalcSubresource(dst_tex_info->base_mip, dst_tex_info->base_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
+		_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
+
+		resolves[num_resolves].src_res = src_tex_info->resource;
+		resolves[num_resolves].src_subres = src_subresource;
+		resolves[num_resolves].dst_res = dst_tex_info->resource;
+		resolves[num_resolves].dst_subres = dst_subresource;
+		resolves[num_resolves].format = RD_TO_D3D12_FORMAT[src_tex_info->format].general_format;
+		num_resolves++;
+	}
+
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	for (uint32_t i = 0; i < num_resolves; i++) {
+		cmd_buf_info->cmd_list->ResolveSubresource(resolves[i].dst_res, resolves[i].dst_subres, resolves[i].src_res, resolves[i].src_subres, resolves[i].format);
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_end_render_pass(CommandBufferID p_cmd_buffer) {
+	_end_render_pass(p_cmd_buffer);
+
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
+
+	const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
+	const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
+
+	if (context->get_vrs_capabilities().ss_image_supported) {
+		ComPtr<ID3D12GraphicsCommandList5> cmd_list_5;
+		cmd_buf_info->cmd_list->QueryInterface(cmd_list_5.GetAddressOf());
+		if (cmd_list_5) {
+			cmd_list_5->RSSetShadingRateImage(nullptr);
+		}
+	}
+
+	if (fb_info->attachments.size()) { // Otherwise, it's screen.
+		for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
+			if (pass_info->attachments[i].store_op == ATTACHMENT_STORE_OP_DONT_CARE) {
+				const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;
+				_discard_texture_subresources(tex_info, cmd_buf_info);
+			}
+		}
+	}
+
+	cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;
+}
+
+void RenderingDeviceDriverD3D12::command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+
+	if (cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX) {
+		cmd_buf_info->render_pass_state.current_subpass = 0;
+	} else {
+		_end_render_pass(p_cmd_buffer);
+		cmd_buf_info->render_pass_state.current_subpass++;
+	}
+
+	const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
+	const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
+	const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];
+
+	D3D12_CPU_DESCRIPTOR_HANDLE *rtv_handles = ALLOCA_ARRAY(D3D12_CPU_DESCRIPTOR_HANDLE, subpass.color_references.size());
+	DescriptorsHeap::Walker rtv_heap_walker = fb_info->rtv_heap.make_walker();
+	for (uint32_t i = 0; i < subpass.color_references.size(); i++) {
+		uint32_t attachment = subpass.color_references[i].attachment;
+		if (attachment == AttachmentReference::UNUSED) {
+			if (!frames[frame_idx].null_rtv_handle.ptr) {
+				// No null descriptor-handle created for this frame yet.
+
+				if (frames[frame_idx].desc_heap_walkers.rtv.is_at_eof()) {
+					if (!frames[frame_idx].desc_heaps_exhausted_reported.rtv) {
+						frames[frame_idx].desc_heaps_exhausted_reported.rtv = true;
+						ERR_FAIL_MSG("Cannot begin subpass because there's no enough room in current frame's RENDER TARGET descriptors heap.\n"
+									 "Please increase the value of the rendering/rendering_device/d3d12/max_misc_descriptors_per_frame project setting.");
+					} else {
+						return;
+					}
+				}
+
+				D3D12_RENDER_TARGET_VIEW_DESC rtv_desc_null = {};
+				rtv_desc_null.Format = DXGI_FORMAT_R8_UINT;
+				rtv_desc_null.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+				frames[frame_idx].null_rtv_handle = frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle();
+				device->CreateRenderTargetView(nullptr, &rtv_desc_null, frames[frame_idx].null_rtv_handle);
+				frames[frame_idx].desc_heap_walkers.rtv.advance();
+			}
+			rtv_handles[i] = frames[frame_idx].null_rtv_handle;
+		} else {
+			uint32_t rt_index = fb_info->attachments_handle_inds[attachment];
+			rtv_heap_walker.rewind();
+			rtv_heap_walker.advance(rt_index);
+			rtv_handles[i] = rtv_heap_walker.get_curr_cpu_handle();
+		}
+	}
+
+	D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = {};
+	{
+		DescriptorsHeap::Walker dsv_heap_walker = fb_info->dsv_heap.make_walker();
+		if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {
+			uint32_t ds_index = fb_info->attachments_handle_inds[subpass.depth_stencil_reference.attachment];
+			dsv_heap_walker.rewind();
+			dsv_heap_walker.advance(ds_index);
+			dsv_handle = dsv_heap_walker.get_curr_cpu_handle();
+		}
+	}
+
+	cmd_buf_info->cmd_list->OMSetRenderTargets(subpass.color_references.size(), rtv_handles, false, dsv_handle.ptr ? &dsv_handle : nullptr);
+}
+
+void RenderingDeviceDriverD3D12::command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+
+	D3D12_VIEWPORT *d3d12_viewports = ALLOCA_ARRAY(D3D12_VIEWPORT, p_viewports.size());
+	for (uint32_t i = 0; i < p_viewports.size(); i++) {
+		d3d12_viewports[i] = CD3DX12_VIEWPORT(
+				p_viewports[i].position.x,
+				p_viewports[i].position.y,
+				p_viewports[i].size.x,
+				p_viewports[i].size.y);
+	}
+
+	cmd_buf_info->cmd_list->RSSetViewports(p_viewports.size(), d3d12_viewports);
+}
+
+void RenderingDeviceDriverD3D12::command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+
+	D3D12_RECT *d3d12_scissors = ALLOCA_ARRAY(D3D12_RECT, p_scissors.size());
+	for (uint32_t i = 0; i < p_scissors.size(); i++) {
+		d3d12_scissors[i] = CD3DX12_RECT(
+				p_scissors[i].position.x,
+				p_scissors[i].position.y,
+				p_scissors[i].position.x + p_scissors[i].size.x,
+				p_scissors[i].position.y + p_scissors[i].size.y);
+	}
+
+	cmd_buf_info->cmd_list->RSSetScissorRects(p_scissors.size(), d3d12_scissors);
+}
+
+void RenderingDeviceDriverD3D12::command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+
+	DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
+	const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
+	const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
+
+	DescriptorsHeap::Walker rtv_heap_walker = fb_info->rtv_heap.make_walker();
+	DescriptorsHeap::Walker dsv_heap_walker = fb_info->dsv_heap.make_walker();
+
+	for (uint32_t i = 0; i < p_attachment_clears.size(); i++) {
+		uint32_t attachment = UINT32_MAX;
+		bool is_render_target = false;
+		if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {
+			attachment = p_attachment_clears[i].color_attachment;
+			is_render_target = true;
+		} else {
+			attachment = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass].depth_stencil_reference.attachment;
+		}
+
+		for (uint32_t j = 0; j < p_rects.size(); j++) {
+			D3D12_RECT rect = CD3DX12_RECT(
+					p_rects[j].position.x,
+					p_rects[j].position.y,
+					p_rects[j].position.x + p_rects[j].size.x,
+					p_rects[j].position.y + p_rects[j].size.y);
+			const D3D12_RECT *rect_ptr = cmd_buf_info->render_pass_state.region_is_all ? nullptr : &rect;
+
+			if (is_render_target) {
+				uint32_t color_idx = fb_info->attachments_handle_inds[attachment];
+				rtv_heap_walker.rewind();
+				rtv_heap_walker.advance(color_idx);
+				cmd_buf_info->cmd_list->ClearRenderTargetView(
+						rtv_heap_walker.get_curr_cpu_handle(),
+						p_attachment_clears[i].value.color.components,
+						rect_ptr ? 1 : 0,
+						rect_ptr);
+			} else {
+				uint32_t depth_stencil_idx = fb_info->attachments_handle_inds[attachment];
+				dsv_heap_walker.rewind();
+				dsv_heap_walker.advance(depth_stencil_idx);
+				D3D12_CLEAR_FLAGS flags = {};
+				if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {
+					flags |= D3D12_CLEAR_FLAG_DEPTH;
+				}
+				if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {
+					flags |= D3D12_CLEAR_FLAG_STENCIL;
+				}
+				cmd_buf_info->cmd_list->ClearDepthStencilView(
+						dsv_heap_walker.get_curr_cpu_handle(),
+						flags,
+						p_attachment_clears[i].value.depth,
+						p_attachment_clears[i].value.stencil,
+						rect_ptr ? 1 : 0,
+						rect_ptr);
+			}
+		}
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
+
+	if (cmd_buf_info->graphics_pso == pso) {
+		return;
+	}
+
+	const ShaderInfo *shader_info_in = pipelines_shaders[pso];
+	const RenderPipelineExtraInfo &pso_extra_info = render_psos_extra_info[pso];
+
+	cmd_buf_info->cmd_list->SetPipelineState(pso);
+	if (cmd_buf_info->graphics_root_signature_crc != shader_info_in->root_signature_crc) {
+		cmd_buf_info->cmd_list->SetGraphicsRootSignature(shader_info_in->root_signature.Get());
+		cmd_buf_info->graphics_root_signature_crc = shader_info_in->root_signature_crc;
+	}
+
+	cmd_buf_info->cmd_list->IASetPrimitiveTopology(pso_extra_info.dyn_params.primitive_topology);
+	cmd_buf_info->cmd_list->OMSetBlendFactor(pso_extra_info.dyn_params.blend_constant.components);
+	cmd_buf_info->cmd_list->OMSetStencilRef(pso_extra_info.dyn_params.stencil_reference);
+
+	ComPtr<ID3D12GraphicsCommandList1> command_list_1;
+	cmd_buf_info->cmd_list->QueryInterface(command_list_1.GetAddressOf());
+	if (command_list_1) {
+		command_list_1->OMSetDepthBounds(pso_extra_info.dyn_params.depth_bounds_min, pso_extra_info.dyn_params.depth_bounds_max);
+	}
+
+	cmd_buf_info->render_pass_state.vf_info = pso_extra_info.vf_info;
+
+	cmd_buf_info->graphics_pso = pso;
+	cmd_buf_info->compute_pso = nullptr;
+}
+
+void RenderingDeviceDriverD3D12::command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+	_command_bind_uniform_set(p_cmd_buffer, p_uniform_set, p_shader, p_set_index, false);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	cmd_buf_info->cmd_list->DrawInstanced(p_vertex_count, p_instance_count, p_base_vertex, p_first_instance);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	cmd_buf_info->cmd_list->DrawIndexedInstanced(p_index_count, p_instance_count, p_first_index, p_vertex_offset, p_first_instance);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
+	_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
+	BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
+	_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
+	_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
+}
+
+void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	_bind_vertex_buffers(cmd_buf_info);
+	BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
+	BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
+	_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
+}
+
+void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+
+	DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
+
+	// Vertex buffer views are set deferredly, to be sure we already know the strides by then,
+	// which is only true once the pipeline has been bound. Otherwise, we'd need that the pipeline
+	// is always bound first, which would be not kind of us. [[DEFERRED_VERTEX_BUFFERS]]
+	DEV_ASSERT(p_binding_count <= ARRAY_SIZE(cmd_buf_info->render_pass_state.vertex_buffer_views));
+	for (uint32_t i = 0; i < p_binding_count; i++) {
+		BufferInfo *buffer_info = (BufferInfo *)p_buffers[i].id;
+
+		cmd_buf_info->render_pass_state.vertex_buffer_views[i] = {};
+		cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + p_offsets[i];
+		cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i];
+
+		_resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
+	}
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->render_pass_state.vertex_buffer_count = p_binding_count;
+}
+
+void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	BufferInfo *buffer_info = (BufferInfo *)p_buffer.id;
+
+	D3D12_INDEX_BUFFER_VIEW d3d12_ib_view = {};
+	d3d12_ib_view.BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + p_offset;
+	d3d12_ib_view.SizeInBytes = buffer_info->size - p_offset;
+	d3d12_ib_view.Format = p_format == INDEX_BUFFER_FORMAT_UINT16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
+
+	_resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+
+	cmd_buf_info->cmd_list->IASetIndexBuffer(&d3d12_ib_view);
+}
+
+// [[DEFERRED_VERTEX_BUFFERS]]
+void RenderingDeviceDriverD3D12::_bind_vertex_buffers(CommandBufferInfo *p_cmd_buf_info) {
+	RenderPassState &render_pass_state = p_cmd_buf_info->render_pass_state;
+	if (render_pass_state.vertex_buffer_count && render_pass_state.vf_info) {
+		for (uint32_t i = 0; i < render_pass_state.vertex_buffer_count; i++) {
+			render_pass_state.vertex_buffer_views[i].StrideInBytes = render_pass_state.vf_info->vertex_buffer_strides[i];
+		}
+		p_cmd_buf_info->cmd_list->IASetVertexBuffers(0, render_pass_state.vertex_buffer_count, render_pass_state.vertex_buffer_views);
+		render_pass_state.vertex_buffer_count = 0;
+	}
+}
+
+void RenderingDeviceDriverD3D12::command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	cmd_buf_info->cmd_list->OMSetBlendFactor(p_constants.components);
+}
+
+void RenderingDeviceDriverD3D12::command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) {
+	if (!Math::is_equal_approx(p_width, 1.0f)) {
+		ERR_FAIL_MSG("Setting line widths other than 1.0 is not supported by the Direct3D 12 rendering driver.");
+	}
+}
+
+// ----- PIPELINE -----
+
+static const D3D12_PRIMITIVE_TOPOLOGY_TYPE RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[RDD::RENDER_PRIMITIVE_MAX] = {
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+	D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
+};
+
+static const D3D12_PRIMITIVE_TOPOLOGY RD_PRIMITIVE_TO_D3D12_TOPOLOGY[RDD::RENDER_PRIMITIVE_MAX] = {
+	D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
+	D3D_PRIMITIVE_TOPOLOGY_LINELIST,
+	D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
+	D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
+	D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
+	D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
+	D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
+	D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
+	D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
+	D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
+	D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
+};
+
+static const D3D12_CULL_MODE RD_POLYGON_CULL_TO_D3D12_CULL_MODE[RDD::POLYGON_CULL_MAX] = {
+	D3D12_CULL_MODE_NONE,
+	D3D12_CULL_MODE_FRONT,
+	D3D12_CULL_MODE_BACK,
+};
+
+static const D3D12_STENCIL_OP RD_TO_D3D12_STENCIL_OP[RDD::STENCIL_OP_MAX] = {
+	D3D12_STENCIL_OP_KEEP,
+	D3D12_STENCIL_OP_ZERO,
+	D3D12_STENCIL_OP_REPLACE,
+	D3D12_STENCIL_OP_INCR_SAT,
+	D3D12_STENCIL_OP_DECR_SAT,
+	D3D12_STENCIL_OP_INVERT,
+	D3D12_STENCIL_OP_INCR,
+	D3D12_STENCIL_OP_DECR,
+};
+
+static const D3D12_LOGIC_OP RD_TO_D3D12_LOGIC_OP[RDD::LOGIC_OP_MAX] = {
+	D3D12_LOGIC_OP_CLEAR,
+	D3D12_LOGIC_OP_AND,
+	D3D12_LOGIC_OP_AND_REVERSE,
+	D3D12_LOGIC_OP_COPY,
+	D3D12_LOGIC_OP_AND_INVERTED,
+	D3D12_LOGIC_OP_NOOP,
+	D3D12_LOGIC_OP_XOR,
+	D3D12_LOGIC_OP_OR,
+	D3D12_LOGIC_OP_NOR,
+	D3D12_LOGIC_OP_EQUIV,
+	D3D12_LOGIC_OP_INVERT,
+	D3D12_LOGIC_OP_OR_REVERSE,
+	D3D12_LOGIC_OP_COPY_INVERTED,
+	D3D12_LOGIC_OP_OR_INVERTED,
+	D3D12_LOGIC_OP_NAND,
+	D3D12_LOGIC_OP_SET,
+};
+
+static const D3D12_BLEND RD_TO_D3D12_BLEND_FACTOR[RDD::BLEND_FACTOR_MAX] = {
+	D3D12_BLEND_ZERO,
+	D3D12_BLEND_ONE,
+	D3D12_BLEND_SRC_COLOR,
+	D3D12_BLEND_INV_SRC_COLOR,
+	D3D12_BLEND_DEST_COLOR,
+	D3D12_BLEND_INV_DEST_COLOR,
+	D3D12_BLEND_SRC_ALPHA,
+	D3D12_BLEND_INV_SRC_ALPHA,
+	D3D12_BLEND_DEST_ALPHA,
+	D3D12_BLEND_INV_DEST_ALPHA,
+	D3D12_BLEND_BLEND_FACTOR,
+	D3D12_BLEND_INV_BLEND_FACTOR,
+	D3D12_BLEND_BLEND_FACTOR,
+	D3D12_BLEND_INV_BLEND_FACTOR,
+	D3D12_BLEND_SRC_ALPHA_SAT,
+	D3D12_BLEND_SRC1_COLOR,
+	D3D12_BLEND_INV_SRC1_COLOR,
+	D3D12_BLEND_SRC1_ALPHA,
+	D3D12_BLEND_INV_SRC1_ALPHA,
+};
+
+static const D3D12_BLEND_OP RD_TO_D3D12_BLEND_OP[RDD::BLEND_OP_MAX] = {
+	D3D12_BLEND_OP_ADD,
+	D3D12_BLEND_OP_SUBTRACT,
+	D3D12_BLEND_OP_REV_SUBTRACT,
+	D3D12_BLEND_OP_MIN,
+	D3D12_BLEND_OP_MAX,
+};
+
+RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
+		ShaderID p_shader,
+		VertexFormatID p_vertex_format,
+		RenderPrimitive p_render_primitive,
+		PipelineRasterizationState p_rasterization_state,
+		PipelineMultisampleState p_multisample_state,
+		PipelineDepthStencilState p_depth_stencil_state,
+		PipelineColorBlendState p_blend_state,
+		VectorView<int32_t> p_color_attachments,
+		BitField<PipelineDynamicStateFlags> p_dynamic_state,
+		RenderPassID p_render_pass,
+		uint32_t p_render_subpass,
+		VectorView<PipelineSpecializationConstant> p_specialization_constants) {
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+
+	CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
+	RenderPipelineExtraInfo pso_extra_info;
+
+	const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
+
+	// Attachments.
+	LocalVector<uint32_t> color_attachments;
+	{
+		const Subpass &subpass = pass_info->subpasses[p_render_subpass];
+
+		for (uint32_t i = 0; i < ARRAY_SIZE((&pipeline_desc.RTVFormats)->RTFormats); i++) {
+			(&pipeline_desc.RTVFormats)->RTFormats[i] = DXGI_FORMAT_UNKNOWN;
+		}
+
+		for (uint32_t i = 0; i < subpass.color_references.size(); i++) {
+			const AttachmentReference &ref = subpass.color_references[i];
+			if (ref.attachment != AttachmentReference::UNUSED) {
+				const Attachment &attachment = pass_info->attachments[ref.attachment];
+				DEV_ASSERT((&pipeline_desc.RTVFormats)->RTFormats[i] == DXGI_FORMAT_UNKNOWN);
+				(&pipeline_desc.RTVFormats)->RTFormats[i] = RD_TO_D3D12_FORMAT[attachment.format].general_format;
+			}
+		}
+		(&pipeline_desc.RTVFormats)->NumRenderTargets = p_color_attachments.size();
+
+		if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {
+			const Attachment &attachment = pass_info->attachments[subpass.depth_stencil_reference.attachment];
+			pipeline_desc.DSVFormat = RD_TO_D3D12_FORMAT[attachment.format].dsv_format;
+		} else {
+			pipeline_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
+		}
+	}
+
+	// Vertex.
+	if (p_vertex_format) {
+		const VertexFormatInfo *vf_info = (const VertexFormatInfo *)p_vertex_format.id;
+		(&pipeline_desc.InputLayout)->pInputElementDescs = vf_info->input_elem_descs.ptr();
+		(&pipeline_desc.InputLayout)->NumElements = vf_info->input_elem_descs.size();
+		pso_extra_info.vf_info = vf_info;
+	}
+
+	// Input assembly & tessellation.
+
+	pipeline_desc.PrimitiveTopologyType = RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[p_render_primitive];
+	if (p_render_primitive == RENDER_PRIMITIVE_TESSELATION_PATCH) {
+		// Is there any way to get the true point count limit?
+		ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > 32, PipelineID());
+		pso_extra_info.dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);
+	} else {
+		pso_extra_info.dyn_params.primitive_topology = RD_PRIMITIVE_TO_D3D12_TOPOLOGY[p_render_primitive];
+	}
+	if (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX) {
+		// TODO: This is right for 16-bit indices; for 32-bit there's a different enum value to set, but we don't know at this point.
+		pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
+	} else {
+		pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
+	}
+
+	// Rasterization.
+	(&pipeline_desc.RasterizerState)->DepthClipEnable = !p_rasterization_state.enable_depth_clamp;
+	// In D3D12, discard can be supported with some extra effort (empty pixel shader + disable depth/stencil test); that said, unsupported by now.
+	ERR_FAIL_COND_V(p_rasterization_state.discard_primitives, PipelineID());
+	(&pipeline_desc.RasterizerState)->FillMode = p_rasterization_state.wireframe ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
+	(&pipeline_desc.RasterizerState)->CullMode = RD_POLYGON_CULL_TO_D3D12_CULL_MODE[p_rasterization_state.cull_mode];
+	(&pipeline_desc.RasterizerState)->FrontCounterClockwise = p_rasterization_state.front_face == POLYGON_FRONT_FACE_COUNTER_CLOCKWISE;
+	// In D3D12, there's still a point in setting up depth bias with no depth buffer, but just zeroing (disabling) it all in such case is closer to Vulkan.
+	if (p_rasterization_state.depth_bias_enabled && pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {
+		(&pipeline_desc.RasterizerState)->DepthBias = p_rasterization_state.depth_bias_constant_factor;
+		(&pipeline_desc.RasterizerState)->DepthBiasClamp = p_rasterization_state.depth_bias_clamp;
+		(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = p_rasterization_state.depth_bias_slope_factor;
+		(&pipeline_desc.RasterizerState)->DepthBias = 0;
+		(&pipeline_desc.RasterizerState)->DepthBiasClamp = 0.0f;
+		(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = 0.0f;
+	}
+	(&pipeline_desc.RasterizerState)->ForcedSampleCount = 0;
+	(&pipeline_desc.RasterizerState)->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+	(&pipeline_desc.RasterizerState)->MultisampleEnable = TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != 1;
+	(&pipeline_desc.RasterizerState)->AntialiasedLineEnable = true;
+
+	// In D3D12, there's no line width.
+	ERR_FAIL_COND_V(!Math::is_equal_approx(p_rasterization_state.line_width, 1.0f), PipelineID());
+
+	// Multisample.
+	ERR_FAIL_COND_V(p_multisample_state.enable_sample_shading, PipelineID()); // How one enables this in D3D12?
+	if ((&pipeline_desc.RTVFormats)->NumRenderTargets || pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {
+		uint32_t sample_count = MIN(
+				pass_info->max_supported_sample_count,
+				TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count]);
+		(&pipeline_desc.SampleDesc)->Count = sample_count;
+	} else {
+		(&pipeline_desc.SampleDesc)->Count = 1;
+	}
+	if ((&pipeline_desc.SampleDesc)->Count > 1) {
+		(&pipeline_desc.SampleDesc)->Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
+	} else {
+		(&pipeline_desc.SampleDesc)->Quality = 0;
+	}
+	if (p_multisample_state.sample_mask.size()) {
+		for (int i = 1; i < p_multisample_state.sample_mask.size(); i++) {
+			// In D3D12 there's a single sample mask for every pixel.
+			ERR_FAIL_COND_V(p_multisample_state.sample_mask[i] != p_multisample_state.sample_mask[0], PipelineID());
+		}
+		pipeline_desc.SampleMask = p_multisample_state.sample_mask[0];
+	} else {
+		pipeline_desc.SampleMask = 0xffffffff;
+	}
+
+	// Depth stencil.
+
+	if (pipeline_desc.DSVFormat == DXGI_FORMAT_UNKNOWN) {
+		(&pipeline_desc.DepthStencilState)->DepthEnable = false;
+		(&pipeline_desc.DepthStencilState)->StencilEnable = false;
+	} else {
+		(&pipeline_desc.DepthStencilState)->DepthEnable = p_depth_stencil_state.enable_depth_test;
+		(&pipeline_desc.DepthStencilState)->DepthWriteMask = p_depth_stencil_state.enable_depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
+		(&pipeline_desc.DepthStencilState)->DepthFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.depth_compare_operator];
+		(&pipeline_desc.DepthStencilState)->DepthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;
+		(&pipeline_desc.DepthStencilState)->StencilEnable = p_depth_stencil_state.enable_stencil;
+
+		// In D3D12 some elements can't be different across front and back.
+		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.compare_mask != p_depth_stencil_state.back_op.compare_mask, PipelineID());
+		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.write_mask != p_depth_stencil_state.back_op.write_mask, PipelineID());
+		ERR_FAIL_COND_V(p_depth_stencil_state.front_op.reference != p_depth_stencil_state.back_op.reference, PipelineID());
+		(&pipeline_desc.DepthStencilState)->StencilReadMask = p_depth_stencil_state.front_op.compare_mask;
+		(&pipeline_desc.DepthStencilState)->StencilWriteMask = p_depth_stencil_state.front_op.write_mask;
+
+		(&pipeline_desc.DepthStencilState)->FrontFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.fail];
+		(&pipeline_desc.DepthStencilState)->FrontFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.pass];
+		(&pipeline_desc.DepthStencilState)->FrontFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.depth_fail];
+		(&pipeline_desc.DepthStencilState)->FrontFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.front_op.compare];
+
+		(&pipeline_desc.DepthStencilState)->BackFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.fail];
+		(&pipeline_desc.DepthStencilState)->BackFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.pass];
+		(&pipeline_desc.DepthStencilState)->BackFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.depth_fail];
+		(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.back_op.compare];
+
+		pso_extra_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
+		pso_extra_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
+		pso_extra_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
+	}
+
+	// Blend states.
+	(&pipeline_desc.BlendState)->AlphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
+	{
+		bool all_attachments_same_blend = true;
+		for (int i = 0; i < p_blend_state.attachments.size(); i++) {
+			const PipelineColorBlendState::Attachment &bs = p_blend_state.attachments[i];
+			D3D12_RENDER_TARGET_BLEND_DESC &bd = (&pipeline_desc.BlendState)->RenderTarget[i];
+
+			bd.BlendEnable = bs.enable_blend;
+			bd.LogicOpEnable = p_blend_state.enable_logic_op;
+			bd.LogicOp = RD_TO_D3D12_LOGIC_OP[p_blend_state.logic_op];
+
+			bd.SrcBlend = RD_TO_D3D12_BLEND_FACTOR[bs.src_color_blend_factor];
+			bd.DestBlend = RD_TO_D3D12_BLEND_FACTOR[bs.dst_color_blend_factor];
+			bd.BlendOp = RD_TO_D3D12_BLEND_OP[bs.color_blend_op];
+
+			bd.SrcBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.src_alpha_blend_factor];
+			bd.DestBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.dst_alpha_blend_factor];
+			bd.BlendOpAlpha = RD_TO_D3D12_BLEND_OP[bs.alpha_blend_op];
+
+			if (bs.write_r) {
+				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED;
+			}
+			if (bs.write_g) {
+				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN;
+			}
+			if (bs.write_b) {
+				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE;
+			}
+			if (bs.write_a) {
+				bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
+			}
+
+			if (i > 0 && all_attachments_same_blend) {
+				all_attachments_same_blend = &(&pipeline_desc.BlendState)->RenderTarget[i] == &(&pipeline_desc.BlendState)->RenderTarget[0];
+			}
+		}
+
+		// Per D3D12 docs, if logic op used, independent blending is not supported.
+		ERR_FAIL_COND_V(p_blend_state.enable_logic_op && !all_attachments_same_blend, PipelineID());
+
+		(&pipeline_desc.BlendState)->IndependentBlendEnable = !all_attachments_same_blend;
+	}
+
+	pso_extra_info.dyn_params.blend_constant = p_blend_state.blend_constant;
+
+	// Stages bytecodes + specialization constants.
+
+	pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();
+
+	HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
+	bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);
+	ERR_FAIL_COND_V(!ok, PipelineID());
+
+	pipeline_desc.VS = D3D12_SHADER_BYTECODE{
+		final_stages_bytecode[SHADER_STAGE_VERTEX].ptr(),
+		(SIZE_T)final_stages_bytecode[SHADER_STAGE_VERTEX].size()
+	};
+	pipeline_desc.PS = D3D12_SHADER_BYTECODE{
+		final_stages_bytecode[SHADER_STAGE_FRAGMENT].ptr(),
+		(SIZE_T)final_stages_bytecode[SHADER_STAGE_FRAGMENT].size()
+	};
+
+	ComPtr<ID3D12Device2> device_2;
+	device->QueryInterface(device_2.GetAddressOf());
+	ID3D12PipelineState *pso = nullptr;
+	HRESULT res = E_FAIL;
+	if (device_2) {
+		D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
+		pssd.pPipelineStateSubobjectStream = &pipeline_desc;
+		pssd.SizeInBytes = sizeof(pipeline_desc);
+		res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(&pso));
+	} else {
+		D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = pipeline_desc.GraphicsDescV0();
+		res = device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso));
+	}
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Graphics)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	// Bookkeep ancillary info.
+
+	pipelines_shaders[pso] = shader_info_in;
+	render_psos_extra_info[pso] = pso_extra_info;
+
+	return PipelineID(pso);
+}
+
+/*****************/
+/**** COMPUTE ****/
+/*****************/
+
+// ----- COMMANDS -----
+
+void RenderingDeviceDriverD3D12::command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
+	CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
+	ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
+	const ShaderInfo *shader_info_in = pipelines_shaders[pso];
+
+	if (cmd_buf_info->compute_pso == pso) {
+		return;
+	}
+
+	cmd_buf_info->cmd_list->SetPipelineState(pso);
+	if (cmd_buf_info->compute_root_signature_crc != shader_info_in->root_signature_crc) {
+		cmd_buf_info->cmd_list->SetComputeRootSignature(shader_info_in->root_signature.Get());
+		cmd_buf_info->compute_root_signature_crc = shader_info_in->root_signature_crc;
+	}
+
+	cmd_buf_info->compute_pso = pso;
+	cmd_buf_info->graphics_pso = nullptr;
+}
+
+void RenderingDeviceDriverD3D12::command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+	_command_bind_uniform_set(p_cmd_buffer, p_uniform_set, p_shader, p_set_index, true);
+}
+
+void RenderingDeviceDriverD3D12::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->Dispatch(p_x_groups, p_y_groups, p_z_groups);
+}
+
+void RenderingDeviceDriverD3D12::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
+	_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
+	_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
+	cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.dispatch.Get(), 1, indirect_buf_info->resource, p_offset, nullptr, 0);
+}
+
+// ----- PIPELINE -----
+
+RDD::PipelineID RenderingDeviceDriverD3D12::compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {
+	const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
+
+	CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
+
+	// Stages bytecodes + specialization constants.
+
+	pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();
+
+	HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
+	bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);
+	ERR_FAIL_COND_V(!ok, PipelineID());
+
+	pipeline_desc.CS = D3D12_SHADER_BYTECODE{
+		final_stages_bytecode[SHADER_STAGE_COMPUTE].ptr(),
+		(SIZE_T)final_stages_bytecode[SHADER_STAGE_COMPUTE].size()
+	};
+
+	ComPtr<ID3D12Device2> device_2;
+	device->QueryInterface(device_2.GetAddressOf());
+	ID3D12PipelineState *pso = nullptr;
+	HRESULT res = E_FAIL;
+	if (device_2) {
+		D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
+		pssd.pPipelineStateSubobjectStream = &pipeline_desc;
+		pssd.SizeInBytes = sizeof(pipeline_desc);
+		res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(&pso));
+	} else {
+		D3D12_COMPUTE_PIPELINE_STATE_DESC desc = pipeline_desc.ComputeDescV0();
+		res = device->CreateComputePipelineState(&desc, IID_PPV_ARGS(&pso));
+	}
+	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Compute)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	// Bookkeep ancillary info.
+
+	pipelines_shaders[pso] = shader_info_in;
+
+	return PipelineID(pso);
+}
+
+/*****************/
+/**** QUERIES ****/
+/*****************/
+
+// ----- TIMESTAMP -----
+
+RDD::QueryPoolID RenderingDeviceDriverD3D12::timestamp_query_pool_create(uint32_t p_query_count) {
+	ComPtr<ID3D12QueryHeap> query_heap;
+	{
+		D3D12_QUERY_HEAP_DESC qh_desc = {};
+		qh_desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
+		qh_desc.Count = p_query_count;
+		qh_desc.NodeMask = 0;
+		HRESULT res = device->CreateQueryHeap(&qh_desc, IID_PPV_ARGS(query_heap.GetAddressOf()));
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "CreateQueryHeap failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	}
+
+	ComPtr<D3D12MA::Allocation> results_buffer_allocation;
+	{
+		D3D12MA::ALLOCATION_DESC allocation_desc = {};
+		allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;
+
+		CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(uint64_t) * p_query_count);
+
+		ComPtr<ID3D12Resource> results_buffer;
+		HRESULT res = allocator->CreateResource(
+				&allocation_desc,
+				&resource_desc,
+				D3D12_RESOURCE_STATE_COPY_DEST,
+				nullptr,
+				results_buffer_allocation.GetAddressOf(),
+				IID_PPV_ARGS(results_buffer.GetAddressOf()));
+		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+	}
+
+	// Bookkeep.
+
+	TimestampQueryPoolInfo *tqp_info = VersatileResource::allocate<TimestampQueryPoolInfo>(resources_allocator);
+	tqp_info->query_heap = query_heap;
+	tqp_info->query_count = p_query_count;
+	tqp_info->results_buffer_allocation = results_buffer_allocation;
+
+	return RDD::QueryPoolID(tqp_info);
+}
+
+void RenderingDeviceDriverD3D12::timestamp_query_pool_free(QueryPoolID p_pool_id) {
+	TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
+	VersatileResource::free(resources_allocator, tqp_info);
+}
+
+void RenderingDeviceDriverD3D12::timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) {
+	TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
+
+	ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();
+
+	void *results_buffer_data = nullptr;
+	results_buffer->Map(0, &VOID_RANGE, &results_buffer_data);
+	memcpy(r_results, results_buffer_data, sizeof(uint64_t) * p_query_count);
+	results_buffer->Unmap(0, &VOID_RANGE);
+}
+
+uint64_t RenderingDeviceDriverD3D12::timestamp_query_result_to_time(uint64_t p_result) {
+	return p_result / (double)context->get_device_limits().timestamp_frequency * 1000000000.0;
+}
+
+void RenderingDeviceDriverD3D12::command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) {
+}
+
+void RenderingDeviceDriverD3D12::command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) {
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
+	ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();
+	cmd_buf_info->cmd_list->EndQuery(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index);
+	cmd_buf_info->cmd_list->ResolveQueryData(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index, tqp_info->query_count, results_buffer, p_index * sizeof(uint64_t));
+}
+
+/****************/
+/**** SCREEN ****/
+/****************/
+
+RDD::DataFormat RenderingDeviceDriverD3D12::screen_get_format() {
+	// Very hacky, but not used often per frame, so I guess ok.
+	DXGI_FORMAT d3d12_format = context->get_screen_format();
+	DataFormat format = DATA_FORMAT_MAX;
+	for (int i = 0; i < DATA_FORMAT_MAX; i++) {
+		if (d3d12_format == RD_TO_D3D12_FORMAT[i].general_format) {
+			format = DataFormat(i);
+			break;
+		}
+	}
+	ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, DATA_FORMAT_MAX);
+	return format;
+}
+
+/********************/
+/**** SUBMISSION ****/
+/********************/
+
+void RenderingDeviceDriverD3D12::begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) {
+	frame_idx = p_frame_index;
+
+	frames_drawn = p_frames_drawn;
+	allocator->SetCurrentFrameIndex(p_frames_drawn);
+
+	frames[frame_idx].desc_heap_walkers.resources.rewind();
+	frames[frame_idx].desc_heap_walkers.samplers.rewind();
+	frames[frame_idx].desc_heap_walkers.aux.rewind();
+	frames[frame_idx].desc_heap_walkers.rtv.rewind();
+	frames[frame_idx].desc_heaps_exhausted_reported = {};
+	frames[frame_idx].null_rtv_handle = { 0 };
+	frames[frame_idx].segment_serial = segment_serial;
+
+	ID3D12DescriptorHeap *heaps[] = {
+		frames[frame_idx].desc_heaps.resources.get_heap(),
+		frames[frame_idx].desc_heaps.samplers.get_heap(),
+	};
+
+	const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
+	cmd_buf_info->cmd_list->SetDescriptorHeaps(2, heaps);
+
+	segment_begun = true;
+}
+
+void RenderingDeviceDriverD3D12::end_segment() {
+	segment_serial++;
+	segment_begun = false;
+}
+
+/**************/
+/**** MISC ****/
+/**************/
+
+void RenderingDeviceDriverD3D12::set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) {
+	switch (p_type) {
+		case OBJECT_TYPE_TEXTURE: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			if (tex_info->owner_info.allocation) {
+				context->set_object_name(tex_info->resource, p_name);
+			}
+		} break;
+		case OBJECT_TYPE_SAMPLER: {
+		} break;
+		case OBJECT_TYPE_BUFFER: {
+			const BufferInfo *buf_info = (const BufferInfo *)p_driver_id.id;
+			context->set_object_name(buf_info->resource, p_name);
+		} break;
+		case OBJECT_TYPE_SHADER: {
+			const ShaderInfo *shader_info_in = (const ShaderInfo *)p_driver_id.id;
+			context->set_object_name(shader_info_in->root_signature.Get(), p_name);
+		} break;
+		case OBJECT_TYPE_UNIFORM_SET: {
+			const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_driver_id.id;
+			if (uniform_set_info->desc_heaps.resources.get_heap()) {
+				context->set_object_name(uniform_set_info->desc_heaps.resources.get_heap(), p_name + " resources heap");
+			}
+			if (uniform_set_info->desc_heaps.samplers.get_heap()) {
+				context->set_object_name(uniform_set_info->desc_heaps.samplers.get_heap(), p_name + " samplers heap");
+			}
+		} break;
+		case OBJECT_TYPE_PIPELINE: {
+			ID3D12PipelineState *pso = (ID3D12PipelineState *)p_driver_id.id;
+			context->set_object_name(pso, p_name);
+		} break;
+		default: {
+			DEV_ASSERT(false);
+		}
+	}
+}
+
+uint64_t RenderingDeviceDriverD3D12::get_resource_native_handle(DriverResource p_type, ID p_driver_id) {
+	switch (p_type) {
+		case DRIVER_RESOURCE_LOGICAL_DEVICE: {
+			return (uint64_t)device;
+		}
+		case DRIVER_RESOURCE_PHYSICAL_DEVICE: {
+			return (uint64_t)context->get_adapter();
+		}
+		case DRIVER_RESOURCE_TOPMOST_OBJECT: {
+			return 0;
+		}
+		case DRIVER_RESOURCE_COMMAND_QUEUE: {
+			return (uint64_t)p_driver_id.id;
+		}
+		case DRIVER_RESOURCE_QUEUE_FAMILY: {
+			return 0;
+		}
+		case DRIVER_RESOURCE_TEXTURE: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->main_texture;
+		} break;
+		case DRIVER_RESOURCE_TEXTURE_VIEW: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->resource;
+		}
+		case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->desc.Format;
+		}
+		case DRIVER_RESOURCE_SAMPLER:
+		case DRIVER_RESOURCE_UNIFORM_SET:
+			return 0;
+		case DRIVER_RESOURCE_BUFFER: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->resource;
+		} break;
+		case DRIVER_RESOURCE_COMPUTE_PIPELINE:
+		case DRIVER_RESOURCE_RENDER_PIPELINE: {
+			return p_driver_id.id;
+		}
+		default: {
+			return 0;
+		}
+	}
+}
+
+uint64_t RenderingDeviceDriverD3D12::get_total_memory_used() {
+	D3D12MA::TotalStatistics stats;
+	allocator->CalculateStatistics(&stats);
+	return stats.Total.Stats.BlockBytes;
+}
+
+uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) {
+	uint64_t safe_unbounded = ((uint64_t)1 << 30);
+	switch (p_limit) {
+		case LIMIT_MAX_BOUND_UNIFORM_SETS:
+			return safe_unbounded;
+		case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:
+			return context->get_device_limits().max_srvs_per_shader_stage;
+		case LIMIT_MAX_UNIFORM_BUFFER_SIZE:
+			return 65536;
+		case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
+		case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
+			return 16384; // Based on max. texture size. Maybe not correct.
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:
+			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:
+			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:
+			return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:
+			return D3D12_CS_THREAD_GROUP_MAX_X;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:
+			return D3D12_CS_THREAD_GROUP_MAX_Y;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
+			return D3D12_CS_THREAD_GROUP_MAX_Z;
+		case LIMIT_SUBGROUP_SIZE:
+		// Note in min/max. Shader model 6.6 supports it (see https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_WaveSize.html),
+		// but at this time I don't know the implications on the transpilation to DXIL, etc.
+		case LIMIT_SUBGROUP_MIN_SIZE:
+		case LIMIT_SUBGROUP_MAX_SIZE: {
+			const D3D12Context::SubgroupCapabilities &subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.size;
+		}
+		case LIMIT_SUBGROUP_IN_SHADERS: {
+			const D3D12Context::SubgroupCapabilities &subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.supported_stages_flags_rd();
+		}
+		case LIMIT_SUBGROUP_OPERATIONS: {
+			const D3D12Context::SubgroupCapabilities &subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.supported_operations_flags_rd();
+		}
+		case LIMIT_VRS_TEXEL_WIDTH:
+		case LIMIT_VRS_TEXEL_HEIGHT: {
+			return context->get_vrs_capabilities().ss_image_tile_size;
+		}
+		default: {
+#ifdef DEV_ENABLED
+			WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");
+#endif
+			return safe_unbounded;
+		}
+	}
+}
+
+uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) {
+	switch (p_trait) {
+		case API_TRAIT_HONORS_PIPELINE_BARRIERS:
+			// TODO:
+			// 1. Map fine/Vulkan/enhanced barriers to legacy barriers as closely as possible
+			//    so there's still some advantage even without enhanced barriers available.
+			// 2. Implement enhanced barriers and return true where available.
+			return 0;
+		case API_TRAIT_SHADER_CHANGE_INVALIDATION:
+			return (uint64_t)SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH;
+		case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT:
+			return D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
+		case API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP:
+			return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
+		case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR:
+			return false;
+		default:
+			return RenderingDeviceDriver::api_trait_get(p_trait);
+	}
+}
+
+bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) {
+	switch (p_feature) {
+		case SUPPORTS_MULTIVIEW: {
+			const RDD::MultiviewCapabilities &multiview_capabilies = context->get_multiview_capabilities();
+			return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
+		} break;
+		case SUPPORTS_FSR_HALF_FLOAT: {
+			return context->get_shader_capabilities().native_16bit_ops && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
+		} break;
+		case SUPPORTS_ATTACHMENT_VRS: {
+			const D3D12Context::VRSCapabilities &vrs_capabilities = context->get_vrs_capabilities();
+			return vrs_capabilities.ss_image_supported;
+		} break;
+		case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: {
+			return true;
+		} break;
+		default: {
+			return false;
+		}
+	}
+}
+
+const RDD::MultiviewCapabilities &RenderingDeviceDriverD3D12::get_multiview_capabilities() {
+	return context->get_multiview_capabilities();
+}
+
+/******************/
+
+RenderingDeviceDriverD3D12::RenderingDeviceDriverD3D12(D3D12Context *p_context, ID3D12Device *p_device, uint32_t p_frame_count) :
+		context(p_context),
+		device(p_device) {
+	D3D12MA::ALLOCATOR_DESC allocator_desc = {};
+	allocator_desc.pDevice = device;
+	allocator_desc.pAdapter = context->get_adapter();
+
+	HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator);
+	ERR_FAIL_COND_MSG(!SUCCEEDED(res), "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+
+	{
+		uint32_t resource_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame");
+		uint32_t sampler_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame");
+		uint32_t misc_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame");
+
+		frames.resize(p_frame_count);
+		for (uint32_t i = 0; i < frames.size(); i++) {
+			Error err = frames[i].desc_heaps.resources.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, resource_descriptors_per_frame, true);
+			ERR_FAIL_COND_MSG(err, "Creating the frame's RESOURCE descriptors heap failed.");
+			err = frames[i].desc_heaps.samplers.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, sampler_descriptors_per_frame, true);
+			ERR_FAIL_COND_MSG(err, "Creating the frame's SAMPLER descriptors heap failed.");
+			err = frames[i].desc_heaps.aux.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, misc_descriptors_per_frame, false);
+			ERR_FAIL_COND_MSG(err, "Creating the frame's AUX descriptors heap failed.");
+			err = frames[i].desc_heaps.rtv.allocate(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, misc_descriptors_per_frame, false);
+			ERR_FAIL_COND_MSG(err, "Creating the frame's RENDER TARGET descriptors heap failed.");
+
+			frames[i].desc_heap_walkers.resources = frames[i].desc_heaps.resources.make_walker();
+			frames[i].desc_heap_walkers.samplers = frames[i].desc_heaps.samplers.make_walker();
+			frames[i].desc_heap_walkers.aux = frames[i].desc_heaps.aux.make_walker();
+			frames[i].desc_heap_walkers.rtv = frames[i].desc_heaps.rtv.make_walker();
+
+			{
+				D3D12MA::ALLOCATION_DESC allocation_desc = {};
+				allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
+
+				CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
+
+				ID3D12Resource *resource = nullptr;
+				res = allocator->CreateResource(
+						&allocation_desc,
+						&resource_desc,
+						D3D12_RESOURCE_STATE_COMMON,
+						nullptr,
+						&frames[frame_idx].aux_resource,
+						IID_PPV_ARGS(&resource));
+				ERR_FAIL_COND_MSG(!SUCCEEDED(res), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+			}
+		}
+	}
+
+	{ // Create command signatures for indirect commands.
+		auto _create_command_signature = [&](D3D12_INDIRECT_ARGUMENT_TYPE p_type, uint32_t p_stride, ComPtr<ID3D12CommandSignature> *r_cmd_sig) {
+			D3D12_INDIRECT_ARGUMENT_DESC iarg_desc = {};
+			iarg_desc.Type = p_type;
+			D3D12_COMMAND_SIGNATURE_DESC cs_desc = {};
+			cs_desc.ByteStride = p_stride;
+			cs_desc.NumArgumentDescs = 1;
+			cs_desc.pArgumentDescs = &iarg_desc;
+			cs_desc.NodeMask = 0;
+			res = device->CreateCommandSignature(&cs_desc, nullptr, IID_PPV_ARGS(r_cmd_sig->GetAddressOf()));
+			ERR_FAIL_COND_MSG(!SUCCEEDED(res), "CreateCommandSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+		};
+		_create_command_signature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, sizeof(D3D12_DRAW_ARGUMENTS), &indirect_cmd_signatures.draw);
+		_create_command_signature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, sizeof(D3D12_DRAW_INDEXED_ARGUMENTS), &indirect_cmd_signatures.draw_indexed);
+		_create_command_signature(D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH, sizeof(D3D12_DISPATCH_ARGUMENTS), &indirect_cmd_signatures.dispatch);
+	}
+
+	glsl_type_singleton_init_or_ref();
+}
+
+RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() {
+	{
+		MutexLock lock(dxil_mutex);
+		for (const KeyValue<int, dxil_validator *> &E : dxil_validators) {
+			dxil_destroy_validator(E.value);
+		}
+	}
+
+	glsl_type_singleton_decref();
+}

+ 858 - 0
drivers/d3d12/rendering_device_driver_d3d12.h

@@ -0,0 +1,858 @@
+/**************************************************************************/
+/*  rendering_device_driver_d3d12.h                                       */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_DEVICE_DRIVER_D3D12_H
+#define RENDERING_DEVICE_DRIVER_D3D12_H
+
+#include "core/templates/hash_map.h"
+#include "core/templates/paged_allocator.h"
+#include "servers/rendering/rendering_device_driver.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif
+
+#include "d3dx12.h"
+#include <dxgi1_6.h>
+#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
+#include "D3D12MemAlloc.h"
+
+#include <wrl/client.h>
+
+#if defined(_MSC_VER) && defined(MemoryBarrier)
+// Annoying define from winnt.h. Reintroduced by some of the headers above.
+#undef MemoryBarrier
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+using Microsoft::WRL::ComPtr;
+
+#define D3D12_BITCODE_OFFSETS_NUM_STAGES 3
+
+struct dxil_validator;
+
+class D3D12Context;
+
+// Design principles:
+// - D3D12 structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply).
+class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
+	friend class D3D12Context; // For FramebufferInfo, RenderPassInfo and CommandBufferInfo.
+
+	/*****************/
+	/**** GENERIC ****/
+	/*****************/
+
+	struct D3D12Format {
+		DXGI_FORMAT family = DXGI_FORMAT_UNKNOWN;
+		DXGI_FORMAT general_format = DXGI_FORMAT_UNKNOWN;
+		UINT swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+		DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN;
+	};
+
+	static const D3D12Format RD_TO_D3D12_FORMAT[RDD::DATA_FORMAT_MAX];
+
+	D3D12Context *context = nullptr;
+	ID3D12Device *device = nullptr; // Owned by the context.
+
+	class DescriptorsHeap {
+		D3D12_DESCRIPTOR_HEAP_DESC desc = {};
+		ComPtr<ID3D12DescriptorHeap> heap;
+		uint32_t handle_size = 0;
+
+	public:
+		class Walker { // Texas Ranger.
+			friend class DescriptorsHeap;
+
+			uint32_t handle_size = 0;
+			uint32_t handle_count = 0;
+			D3D12_CPU_DESCRIPTOR_HANDLE first_cpu_handle = {};
+			D3D12_GPU_DESCRIPTOR_HANDLE first_gpu_handle = {};
+			uint32_t handle_index = 0;
+
+		public:
+			D3D12_CPU_DESCRIPTOR_HANDLE get_curr_cpu_handle();
+			D3D12_GPU_DESCRIPTOR_HANDLE get_curr_gpu_handle();
+			_FORCE_INLINE_ void rewind() { handle_index = 0; }
+			void advance(uint32_t p_count = 1);
+			uint32_t get_current_handle_index() const { return handle_index; }
+			uint32_t get_free_handles() { return handle_count - handle_index; }
+			bool is_at_eof() { return handle_index == handle_count; }
+		};
+
+		Error allocate(ID3D12Device *m_device, D3D12_DESCRIPTOR_HEAP_TYPE m_type, uint32_t m_descriptor_count, bool p_for_gpu);
+		uint32_t get_descriptor_count() const { return desc.NumDescriptors; }
+		ID3D12DescriptorHeap *get_heap() const { return heap.Get(); }
+
+		Walker make_walker() const;
+	};
+
+	struct {
+		ComPtr<ID3D12CommandSignature> draw;
+		ComPtr<ID3D12CommandSignature> draw_indexed;
+		ComPtr<ID3D12CommandSignature> dispatch;
+	} indirect_cmd_signatures;
+
+	/****************/
+	/**** MEMORY ****/
+	/****************/
+
+	ComPtr<D3D12MA::Allocator> allocator;
+
+#define USE_SMALL_ALLOCS_POOL // Disabled by now; seems not to be beneficial as it is in Vulkan.
+#ifdef USE_SMALL_ALLOCS_POOL
+	union AllocPoolKey {
+		struct {
+			D3D12_HEAP_TYPE heap_type;
+			D3D12_HEAP_FLAGS heap_flags;
+		};
+		uint64_t key = 0;
+	};
+	HashMap<uint64_t, ComPtr<D3D12MA::Pool>> small_allocs_pools;
+
+	D3D12MA::Pool *_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags);
+#endif
+
+	/******************/
+	/**** RESOURCE ****/
+	/******************/
+
+	struct ResourceInfo {
+		struct States {
+			// As many subresources as mipmaps * layers; planes (for depth-stencil) are tracked together.
+			TightLocalVector<D3D12_RESOURCE_STATES> subresource_states; // Used only if not a view.
+			uint32_t last_batch_transitioned_to_uav = 0;
+			uint32_t last_batch_with_uav_barrier = 0;
+		};
+
+		ID3D12Resource *resource = nullptr; // Non-null even if a view.
+		struct {
+			ComPtr<ID3D12Resource> resource;
+			ComPtr<D3D12MA::Allocation> allocation;
+			States states;
+		} owner_info; // All empty if a view.
+		States *states_ptr = nullptr; // Own or from another if a view.
+	};
+
+	struct BarrierRequest {
+		static const uint32_t MAX_GROUPS = 4;
+		// Maybe this is too much data to have it locally. Benchmarking may reveal that
+		// cache would be used better by having a maximum of local subresource masks and beyond
+		// that have an allocated vector with the rest.
+		static const uint32_t MAX_SUBRESOURCES = 4096;
+		ID3D12Resource *dx_resource = nullptr;
+		uint8_t subres_mask_qwords = 0;
+		uint8_t planes = 0;
+		struct Group {
+			D3D12_RESOURCE_STATES states = {};
+			static_assert(MAX_SUBRESOURCES % 64 == 0);
+			uint64_t subres_mask[MAX_SUBRESOURCES / 64] = {};
+		} groups[MAX_GROUPS];
+		uint8_t groups_count = 0;
+		static const D3D12_RESOURCE_STATES DELETED_GROUP = D3D12_RESOURCE_STATE_COMMON;
+	};
+	PagedAllocator<HashMapElement<ResourceInfo::States *, BarrierRequest>> res_barriers_requests_allocator;
+	HashMap<ResourceInfo::States *, BarrierRequest, HashMapHasherDefault, HashMapComparatorDefault<ResourceInfo::States *>, decltype(res_barriers_requests_allocator)> res_barriers_requests;
+
+	LocalVector<D3D12_RESOURCE_BARRIER> res_barriers;
+	uint32_t res_barriers_count = 0;
+	uint32_t res_barriers_batch = 0;
+#ifdef DEV_ENABLED
+	int frame_barriers_count = 0;
+	int frame_barriers_batches_count = 0;
+	uint64_t frame_barriers_cpu_time = 0;
+#endif
+
+	void _resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override = nullptr);
+	void _resource_transitions_flush(ID3D12GraphicsCommandList *p_cmd_list);
+
+	/*****************/
+	/**** BUFFERS ****/
+	/*****************/
+
+	struct BufferInfo : public ResourceInfo {
+		DataFormat texel_format = DATA_FORMAT_MAX;
+		uint64_t size = 0;
+		struct {
+			bool usable_as_uav : 1;
+			bool is_for_upload : 1;
+		} flags = {};
+	};
+
+public:
+	virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) override final;
+	virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) override final;
+	virtual void buffer_free(BufferID p_buffer) override final;
+	virtual uint64_t buffer_get_allocation_size(BufferID p_buffer) override final;
+	virtual uint8_t *buffer_map(BufferID p_buffer) override final;
+	virtual void buffer_unmap(BufferID p_buffer) override final;
+
+	/*****************/
+	/**** TEXTURE ****/
+	/*****************/
+private:
+	struct TextureInfo : public ResourceInfo {
+		DataFormat format = DATA_FORMAT_MAX;
+		CD3DX12_RESOURCE_DESC desc = {};
+		uint32_t base_layer = 0;
+		uint32_t layers = 0;
+		uint32_t base_mip = 0;
+		uint32_t mipmaps = 0;
+
+		struct {
+			D3D12_SHADER_RESOURCE_VIEW_DESC srv;
+			D3D12_UNORDERED_ACCESS_VIEW_DESC uav;
+		} view_descs = {};
+
+		ID3D12Resource *main_texture = nullptr;
+		struct {
+			D3D12_UNORDERED_ACCESS_VIEW_DESC main_uav_desc;
+			struct {
+				HashMap<DXGI_FORMAT, ComPtr<ID3D12Resource>> aliases; // Key is the DXGI format family.
+			} owner_info = {};
+		} aliasing_hack = {}; // [[CROSS_FAMILY_ALIASING]]
+
+		UINT mapped_subresource = UINT_MAX;
+	};
+
+	HashMap<DXGI_FORMAT, uint32_t> format_sample_counts_mask_cache;
+
+	uint32_t _find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats);
+	UINT _compute_component_mapping(const TextureView &p_view);
+	UINT _compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits);
+	UINT _compute_plane_slice(DataFormat p_format, TextureAspect p_aspect);
+
+	struct CommandBufferInfo;
+	void _discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info);
+
+public:
+	virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) override final;
+	virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
+	virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
+	virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
+	virtual void texture_free(TextureID p_texture) override final;
+	virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
+	virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
+	virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final;
+	virtual void texture_unmap(TextureID p_texture) override final;
+	virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final;
+
+	/*****************/
+	/**** SAMPLER ****/
+	/*****************/
+private:
+	LocalVector<D3D12_SAMPLER_DESC> samplers;
+
+public:
+	virtual SamplerID sampler_create(const SamplerState &p_state) final override;
+	virtual void sampler_free(SamplerID p_sampler) final override;
+	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) override final;
+
+	/**********************/
+	/**** VERTEX ARRAY ****/
+	/**********************/
+private:
+	struct VertexFormatInfo {
+		TightLocalVector<D3D12_INPUT_ELEMENT_DESC> input_elem_descs;
+		TightLocalVector<UINT> vertex_buffer_strides;
+	};
+
+public:
+	virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
+	virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
+
+	/******************/
+	/**** BARRIERS ****/
+	/******************/
+
+	virtual void command_pipeline_barrier(
+			CommandBufferID p_cmd_buffer,
+			BitField<RDD::PipelineStageBits> p_src_stages,
+			BitField<RDD::PipelineStageBits> p_dst_stages,
+			VectorView<RDD::MemoryBarrier> p_memory_barriers,
+			VectorView<RDD::BufferBarrier> p_buffer_barriers,
+			VectorView<RDD::TextureBarrier> p_texture_barriers) override final;
+
+	/*************************/
+	/**** COMMAND BUFFERS ****/
+	/*************************/
+
+	// ----- POOL -----
+
+	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) override final;
+	virtual void command_pool_free(CommandPoolID p_cmd_pool) override final;
+
+	// ----- BUFFER -----
+
+private:
+	// Belongs to RENDERING-SUBPASS, but needed here.
+	struct FramebufferInfo;
+	struct RenderPassInfo;
+	struct RenderPassState {
+		uint32_t current_subpass = UINT32_MAX;
+		const FramebufferInfo *fb_info = nullptr;
+		const RenderPassInfo *pass_info = nullptr;
+		CD3DX12_RECT region_rect = {};
+		bool region_is_all = false;
+
+		const VertexFormatInfo *vf_info = nullptr;
+		D3D12_VERTEX_BUFFER_VIEW vertex_buffer_views[8] = {};
+		uint32_t vertex_buffer_count = 0;
+	};
+
+	// Leveraging knowledge of actual usage and D3D12 specifics (namely, command lists from the same allocator
+	// can't be freely begun and ended), an allocator per list works better.
+	struct CommandBufferInfo {
+		ComPtr<ID3D12CommandAllocator> cmd_allocator;
+		ComPtr<ID3D12GraphicsCommandList> cmd_list;
+
+		ID3D12PipelineState *graphics_pso = nullptr;
+		ID3D12PipelineState *compute_pso = nullptr;
+
+		uint32_t graphics_root_signature_crc = 0;
+		uint32_t compute_root_signature_crc = 0;
+
+		RenderPassState render_pass_state;
+	};
+	RBMap<CommandPoolID, LocalVector<CommandBufferInfo *>> pools_command_buffers;
+	CommandPoolID last_command_pool_id;
+
+public:
+	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) override final;
+	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) override final;
+	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) override final;
+	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) override final;
+	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) override final;
+
+	/*********************/
+	/**** FRAMEBUFFER ****/
+	/*********************/
+private:
+	struct FramebufferInfo {
+		bool is_screen = false;
+		Size2i size;
+		TightLocalVector<uint32_t> attachments_handle_inds; // RTV heap index for color; DSV heap index for DSV.
+		DescriptorsHeap rtv_heap;
+		DescriptorsHeap dsv_heap; // Used only if not for screen and some depth-stencil attachments.
+
+		TightLocalVector<TextureID> attachments; // Color and depth-stencil. Used if not screen.
+		TextureID vrs_attachment;
+	};
+
+	D3D12_RENDER_TARGET_VIEW_DESC _make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases = true);
+	D3D12_DEPTH_STENCIL_VIEW_DESC _make_dsv_for_texture(const TextureInfo *p_texture_info);
+
+public:
+	virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) override final;
+	virtual void framebuffer_free(FramebufferID p_framebuffer) override final;
+
+	/****************/
+	/**** SHADER ****/
+	/****************/
+private:
+	static const uint32_t ROOT_SIGNATURE_SIZE = 256;
+	static const uint32_t PUSH_CONSTANT_SIZE = 128; // Mimicking Vulkan.
+
+	enum {
+		// We can only aim to set a maximum here, since depending on the shader
+		// there may be more or less root signature free for descriptor tables.
+		// Therefore, we'll have to rely on the final check at runtime, when building
+		// the root signature structure for a given shader.
+		// To be precise, these may be present or not, and their size vary statically:
+		// - Push constant (we'll assume this is always present to avoid reserving much
+		//   more space for descriptor sets than needed for almost any imaginable case,
+		//   given that most shader templates feature push constants).
+		// - NIR-DXIL runtime data.
+		MAX_UNIFORM_SETS = (ROOT_SIGNATURE_SIZE - PUSH_CONSTANT_SIZE) / sizeof(uint32_t),
+	};
+
+	enum RootSignatureLocationType {
+		RS_LOC_TYPE_RESOURCE,
+		RS_LOC_TYPE_SAMPLER,
+	};
+
+	enum ResourceClass {
+		RES_CLASS_INVALID,
+		RES_CLASS_CBV,
+		RES_CLASS_SRV,
+		RES_CLASS_UAV,
+	};
+
+	struct ShaderBinary {
+		// Version 1: Initial.
+		// Version 2: 64-bit vertex input mask.
+		// Version 3: Added SC stage mask.
+		static const uint32_t VERSION = 3;
+
+		// Phase 1: SPIR-V reflection, where the Vulkan/RD interface of the shader is discovered.
+		// Phase 2: SPIR-V to DXIL translation, where the DXIL interface is discovered, which may have gaps due to optimizations.
+
+		struct DataBinding {
+			// - Phase 1.
+			uint32_t type = 0;
+			uint32_t binding = 0;
+			uint32_t stages = 0;
+			uint32_t length = 0; // Size of arrays (in total elements), or ubos (in bytes * total elements).
+			uint32_t writable = 0;
+			// - Phase 2.
+			uint32_t res_class = 0;
+			uint32_t has_sampler = 0;
+			uint32_t dxil_stages = 0;
+			struct RootSignatureLocation {
+				uint32_t root_param_idx = UINT32_MAX; // UINT32_MAX if unused.
+				uint32_t range_idx = UINT32_MAX; // UINT32_MAX if unused.
+			};
+			RootSignatureLocation root_sig_locations[2]; // Index is RootSignatureLocationType.
+
+			// We need to sort these to fill the root signature locations properly.
+			bool operator<(const DataBinding &p_other) const {
+				return binding < p_other.binding;
+			}
+		};
+
+		struct SpecializationConstant {
+			// - Phase 1.
+			uint32_t type = 0;
+			uint32_t constant_id = 0;
+			union {
+				uint32_t int_value = 0;
+				float float_value;
+				bool bool_value;
+			};
+			uint32_t stage_flags = 0;
+			// - Phase 2.
+			uint64_t stages_bit_offsets[D3D12_BITCODE_OFFSETS_NUM_STAGES] = {};
+		};
+
+		struct Data {
+			uint64_t vertex_input_mask = 0;
+			uint32_t fragment_output_mask = 0;
+			uint32_t specialization_constants_count = 0;
+			uint32_t spirv_specialization_constants_ids_mask = 0;
+			uint32_t is_compute = 0;
+			uint32_t compute_local_size[3] = {};
+			uint32_t set_count = 0;
+			uint32_t push_constant_size = 0;
+			uint32_t dxil_push_constant_stages = 0; // Phase 2.
+			uint32_t nir_runtime_data_root_param_idx = 0; // Phase 2.
+			uint32_t stage_count = 0;
+			uint32_t shader_name_len = 0;
+			uint32_t root_signature_len = 0;
+			uint32_t root_signature_crc = 0;
+		};
+	};
+
+	struct ShaderInfo {
+		uint32_t dxil_push_constant_size = 0;
+		uint32_t nir_runtime_data_root_param_idx = UINT32_MAX;
+		bool is_compute = false;
+
+		struct UniformBindingInfo {
+			uint32_t stages = 0; // Actual shader stages using the uniform (0 if totally optimized out).
+			ResourceClass res_class = RES_CLASS_INVALID;
+			UniformType type = UNIFORM_TYPE_MAX;
+			uint32_t length = UINT32_MAX;
+#ifdef DEV_ENABLED
+			bool writable = false;
+#endif
+			struct RootSignatureLocation {
+				uint32_t root_param_idx = UINT32_MAX;
+				uint32_t range_idx = UINT32_MAX;
+			};
+			struct {
+				RootSignatureLocation resource;
+				RootSignatureLocation sampler;
+			} root_sig_locations;
+		};
+
+		struct UniformSet {
+			TightLocalVector<UniformBindingInfo> bindings;
+			struct {
+				uint32_t resources = 0;
+				uint32_t samplers = 0;
+			} num_root_params;
+		};
+
+		TightLocalVector<UniformSet> sets;
+
+		struct SpecializationConstant {
+			uint32_t constant_id = UINT32_MAX;
+			uint32_t int_value = UINT32_MAX;
+			uint64_t stages_bit_offsets[D3D12_BITCODE_OFFSETS_NUM_STAGES] = {};
+		};
+
+		TightLocalVector<SpecializationConstant> specialization_constants;
+		uint32_t spirv_specialization_constants_ids_mask = 0;
+
+		HashMap<ShaderStage, Vector<uint8_t>> stages_bytecode;
+
+		ComPtr<ID3D12RootSignature> root_signature;
+		ComPtr<ID3D12RootSignatureDeserializer> root_signature_deserializer;
+		const D3D12_ROOT_SIGNATURE_DESC *root_signature_desc = nullptr; // Owned by the deserializer.
+		uint32_t root_signature_crc = 0;
+	};
+
+	Mutex dxil_mutex;
+	HashMap<int, dxil_validator *> dxil_validators; // One per WorkerThreadPool thread used for shader compilation, plus one (-1) for all the other.
+
+	dxil_validator *_get_dxil_validator_for_current_thread();
+	uint32_t _shader_patch_dxil_specialization_constant(
+			PipelineSpecializationConstantType p_type,
+			const void *p_value,
+			const uint64_t (&p_stages_bit_offsets)[D3D12_BITCODE_OFFSETS_NUM_STAGES],
+			HashMap<ShaderStage, Vector<uint8_t>> &r_stages_bytecodes,
+			bool p_is_first_patch);
+	bool _shader_apply_specialization_constants(
+			const ShaderInfo *p_shader_info,
+			VectorView<PipelineSpecializationConstant> p_specialization_constants,
+			HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode);
+	bool _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob);
+
+public:
+	virtual String shader_get_binary_cache_key() override final;
+	virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) override final;
+	virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
+	virtual uint32_t shader_get_layout_hash(ShaderID p_shader) override final;
+	virtual void shader_free(ShaderID p_shader) override final;
+
+	/*********************/
+	/**** UNIFORM SET ****/
+	/*********************/
+
+private:
+	struct RootDescriptorTable {
+		uint32_t root_param_idx = UINT32_MAX;
+		D3D12_GPU_DESCRIPTOR_HANDLE start_gpu_handle = {};
+	};
+
+	struct UniformSetInfo {
+		struct {
+			DescriptorsHeap resources;
+			DescriptorsHeap samplers;
+		} desc_heaps;
+
+		struct StateRequirement {
+			ResourceInfo *resource = nullptr;
+			bool is_buffer = false;
+			D3D12_RESOURCE_STATES states = {};
+			uint64_t shader_uniform_idx_mask = 0;
+		};
+		TightLocalVector<StateRequirement> resource_states;
+
+		struct RecentBind {
+			uint64_t segment_serial = 0;
+			uint32_t root_signature_crc = 0;
+			struct {
+				TightLocalVector<RootDescriptorTable> resources;
+				TightLocalVector<RootDescriptorTable> samplers;
+			} root_tables;
+			int uses = 0;
+		} recent_binds[4]; // A better amount may be empirically found.
+
+#ifdef DEV_ENABLED
+		// Filthy, but useful for dev.
+		struct ResourceDescInfo {
+			D3D12_DESCRIPTOR_RANGE_TYPE type;
+			D3D12_SRV_DIMENSION srv_dimension;
+		};
+		TightLocalVector<ResourceDescInfo> resources_desc_info;
+#endif
+	};
+
+public:
+	virtual UniformSetID uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) override final;
+	virtual void uniform_set_free(UniformSetID p_uniform_set) override final;
+
+	// ----- COMMANDS -----
+
+	virtual void command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+private:
+	void _command_bind_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index, bool p_for_compute);
+
+public:
+	/******************/
+	/**** TRANSFER ****/
+	/******************/
+
+	virtual void command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) override final;
+	virtual void command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) override final;
+
+	virtual void command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) override final;
+	virtual void command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) override final;
+	virtual void command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) override final;
+
+	virtual void command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) override final;
+	virtual void command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) override final;
+
+	/******************/
+	/**** PIPELINE ****/
+	/******************/
+
+	virtual void pipeline_free(PipelineID p_pipeline) override final;
+
+private:
+	HashMap<ID3D12PipelineState *, const ShaderInfo *> pipelines_shaders;
+
+public:
+	// ----- BINDING -----
+
+	virtual void command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView<uint32_t> p_data) override final;
+
+	// ----- CACHE -----
+
+	virtual bool pipeline_cache_create(const Vector<uint8_t> &p_data) override final;
+	virtual void pipeline_cache_free() override final;
+	virtual size_t pipeline_cache_query_size() override final;
+	virtual Vector<uint8_t> pipeline_cache_serialize() override final;
+
+	/*******************/
+	/**** RENDERING ****/
+	/*******************/
+
+	// ----- SUBPASS -----
+
+private:
+	struct RenderPassInfo {
+		TightLocalVector<Attachment> attachments;
+		TightLocalVector<Subpass> subpasses;
+		uint32_t view_count = 0;
+		uint32_t max_supported_sample_count = 0;
+	};
+
+public:
+	virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
+	virtual void render_pass_free(RenderPassID p_render_pass) override final;
+
+	// ----- COMMANDS -----
+
+	virtual void command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) override final;
+
+private:
+	void _end_render_pass(CommandBufferID p_cmd_buffer);
+
+public:
+	virtual void command_end_render_pass(CommandBufferID p_cmd_buffer) override final;
+	virtual void command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) override final;
+	virtual void command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) override final;
+	virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) override final;
+
+	virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) override final;
+
+	// Binding.
+	virtual void command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
+	virtual void command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+	// Drawing.
+	virtual void command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) override final;
+	virtual void command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) override final;
+	virtual void command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
+
+	// Buffer binding.
+	virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
+	virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
+
+private:
+	void _bind_vertex_buffers(CommandBufferInfo *p_cmd_buf_info);
+
+public:
+	// Dynamic state.
+	virtual void command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) override final;
+	virtual void command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) override final;
+
+	// ----- PIPELINE -----
+
+private:
+	struct RenderPipelineExtraInfo {
+		struct {
+			D3D12_PRIMITIVE_TOPOLOGY primitive_topology = {};
+			Color blend_constant;
+			float depth_bounds_min = 0.0f;
+			float depth_bounds_max = 0.0f;
+			uint32_t stencil_reference = 0;
+		} dyn_params;
+
+		const VertexFormatInfo *vf_info = nullptr;
+	};
+	HashMap<ID3D12PipelineState *, RenderPipelineExtraInfo> render_psos_extra_info;
+
+public:
+	virtual PipelineID render_pipeline_create(
+			ShaderID p_shader,
+			VertexFormatID p_vertex_format,
+			RenderPrimitive p_render_primitive,
+			PipelineRasterizationState p_rasterization_state,
+			PipelineMultisampleState p_multisample_state,
+			PipelineDepthStencilState p_depth_stencil_state,
+			PipelineColorBlendState p_blend_state,
+			VectorView<int32_t> p_color_attachments,
+			BitField<PipelineDynamicStateFlags> p_dynamic_state,
+			RenderPassID p_render_pass,
+			uint32_t p_render_subpass,
+			VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
+
+	/*****************/
+	/**** COMPUTE ****/
+	/*****************/
+
+	// ----- COMMANDS -----
+
+	// Binding.
+	virtual void command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
+	virtual void command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+	// Dispatching.
+	virtual void command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) override final;
+	virtual void command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) override final;
+
+	// ----- PIPELINE -----
+
+	virtual PipelineID compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
+
+	/*****************/
+	/**** QUERIES ****/
+	/*****************/
+
+	// ----- TIMESTAMP -----
+
+private:
+	struct TimestampQueryPoolInfo {
+		ComPtr<ID3D12QueryHeap> query_heap;
+		uint32_t query_count = 0;
+		ComPtr<D3D12MA::Allocation> results_buffer_allocation;
+	};
+
+public:
+	// Basic.
+	virtual QueryPoolID timestamp_query_pool_create(uint32_t p_query_count) override final;
+	virtual void timestamp_query_pool_free(QueryPoolID p_pool_id) override final;
+	virtual void timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) override final;
+	virtual uint64_t timestamp_query_result_to_time(uint64_t p_result) override final;
+
+	// Commands.
+	virtual void command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) override final;
+	virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final;
+
+	/****************/
+	/**** SCREEN ****/
+	/****************/
+
+	virtual DataFormat screen_get_format() override final;
+
+	/********************/
+	/**** SUBMISSION ****/
+	/********************/
+private:
+	struct FrameInfo {
+		struct {
+			DescriptorsHeap resources;
+			DescriptorsHeap samplers;
+			DescriptorsHeap aux;
+			DescriptorsHeap rtv;
+		} desc_heaps;
+		struct {
+			DescriptorsHeap::Walker resources;
+			DescriptorsHeap::Walker samplers;
+			DescriptorsHeap::Walker aux;
+			DescriptorsHeap::Walker rtv;
+		} desc_heap_walkers;
+		struct {
+			bool resources = false;
+			bool samplers = false;
+			bool aux = false;
+			bool rtv = false;
+		} desc_heaps_exhausted_reported;
+		CD3DX12_CPU_DESCRIPTOR_HANDLE null_rtv_handle = {}; // For [[MANUAL_SUBPASSES]].
+		ComPtr<D3D12MA::Allocation> aux_resource;
+		uint32_t segment_serial = 0;
+
+#ifdef DEV_ENABLED
+		uint32_t uniform_set_reused = 0;
+#endif
+	};
+	TightLocalVector<FrameInfo> frames;
+	uint32_t frame_idx = 0;
+	uint32_t frames_drawn = 0;
+	uint32_t segment_serial = 0;
+	bool segment_begun = false;
+
+public:
+	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
+	virtual void end_segment() override final;
+
+	/**************/
+	/**** MISC ****/
+	/**************/
+
+	virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) override final;
+	virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) override final;
+	virtual uint64_t get_total_memory_used() override final;
+	virtual uint64_t limit_get(Limit p_limit) override final;
+	virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
+	virtual bool has_feature(Features p_feature) override final;
+	virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
+
+private:
+	/*********************/
+	/**** BOOKKEEPING ****/
+	/*********************/
+
+	using VersatileResource = VersatileResourceTemplate<
+			BufferInfo,
+			TextureInfo,
+			TextureInfo,
+			TextureInfo,
+			VertexFormatInfo,
+			CommandBufferInfo,
+			FramebufferInfo,
+			ShaderInfo,
+			UniformSetInfo,
+			RenderPassInfo,
+			TimestampQueryPoolInfo>;
+	PagedAllocator<VersatileResource> resources_allocator;
+
+	/******************/
+
+public:
+	RenderingDeviceDriverD3D12(D3D12Context *p_context, ID3D12Device *p_device, uint32_t p_frame_count);
+	virtual ~RenderingDeviceDriverD3D12();
+};
+
+#endif // RENDERING_DEVICE_DRIVER_D3D12_H

+ 2 - 0
drivers/vulkan/SCsub

@@ -2,6 +2,8 @@
 
 Import("env")
 
+env.Append(CPPDEFINES=["RD_ENABLED"])
+
 thirdparty_obj = []
 thirdparty_dir = "#thirdparty/vulkan"
 thirdparty_volk_dir = "#thirdparty/volk"

+ 3350 - 0
drivers/vulkan/rendering_device_driver_vulkan.cpp

@@ -0,0 +1,3350 @@
+/**************************************************************************/
+/*  rendering_device_driver_vulkan.cpp                                    */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_device_driver_vulkan.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/marshalls.h"
+#include "thirdparty/misc/smolv.h"
+#include "vulkan_context.h"
+
+/*****************/
+/**** GENERIC ****/
+/*****************/
+
+static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = {
+	VK_FORMAT_R4G4_UNORM_PACK8,
+	VK_FORMAT_R4G4B4A4_UNORM_PACK16,
+	VK_FORMAT_B4G4R4A4_UNORM_PACK16,
+	VK_FORMAT_R5G6B5_UNORM_PACK16,
+	VK_FORMAT_B5G6R5_UNORM_PACK16,
+	VK_FORMAT_R5G5B5A1_UNORM_PACK16,
+	VK_FORMAT_B5G5R5A1_UNORM_PACK16,
+	VK_FORMAT_A1R5G5B5_UNORM_PACK16,
+	VK_FORMAT_R8_UNORM,
+	VK_FORMAT_R8_SNORM,
+	VK_FORMAT_R8_USCALED,
+	VK_FORMAT_R8_SSCALED,
+	VK_FORMAT_R8_UINT,
+	VK_FORMAT_R8_SINT,
+	VK_FORMAT_R8_SRGB,
+	VK_FORMAT_R8G8_UNORM,
+	VK_FORMAT_R8G8_SNORM,
+	VK_FORMAT_R8G8_USCALED,
+	VK_FORMAT_R8G8_SSCALED,
+	VK_FORMAT_R8G8_UINT,
+	VK_FORMAT_R8G8_SINT,
+	VK_FORMAT_R8G8_SRGB,
+	VK_FORMAT_R8G8B8_UNORM,
+	VK_FORMAT_R8G8B8_SNORM,
+	VK_FORMAT_R8G8B8_USCALED,
+	VK_FORMAT_R8G8B8_SSCALED,
+	VK_FORMAT_R8G8B8_UINT,
+	VK_FORMAT_R8G8B8_SINT,
+	VK_FORMAT_R8G8B8_SRGB,
+	VK_FORMAT_B8G8R8_UNORM,
+	VK_FORMAT_B8G8R8_SNORM,
+	VK_FORMAT_B8G8R8_USCALED,
+	VK_FORMAT_B8G8R8_SSCALED,
+	VK_FORMAT_B8G8R8_UINT,
+	VK_FORMAT_B8G8R8_SINT,
+	VK_FORMAT_B8G8R8_SRGB,
+	VK_FORMAT_R8G8B8A8_UNORM,
+	VK_FORMAT_R8G8B8A8_SNORM,
+	VK_FORMAT_R8G8B8A8_USCALED,
+	VK_FORMAT_R8G8B8A8_SSCALED,
+	VK_FORMAT_R8G8B8A8_UINT,
+	VK_FORMAT_R8G8B8A8_SINT,
+	VK_FORMAT_R8G8B8A8_SRGB,
+	VK_FORMAT_B8G8R8A8_UNORM,
+	VK_FORMAT_B8G8R8A8_SNORM,
+	VK_FORMAT_B8G8R8A8_USCALED,
+	VK_FORMAT_B8G8R8A8_SSCALED,
+	VK_FORMAT_B8G8R8A8_UINT,
+	VK_FORMAT_B8G8R8A8_SINT,
+	VK_FORMAT_B8G8R8A8_SRGB,
+	VK_FORMAT_A8B8G8R8_UNORM_PACK32,
+	VK_FORMAT_A8B8G8R8_SNORM_PACK32,
+	VK_FORMAT_A8B8G8R8_USCALED_PACK32,
+	VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
+	VK_FORMAT_A8B8G8R8_UINT_PACK32,
+	VK_FORMAT_A8B8G8R8_SINT_PACK32,
+	VK_FORMAT_A8B8G8R8_SRGB_PACK32,
+	VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+	VK_FORMAT_A2R10G10B10_SNORM_PACK32,
+	VK_FORMAT_A2R10G10B10_USCALED_PACK32,
+	VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
+	VK_FORMAT_A2R10G10B10_UINT_PACK32,
+	VK_FORMAT_A2R10G10B10_SINT_PACK32,
+	VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+	VK_FORMAT_A2B10G10R10_SNORM_PACK32,
+	VK_FORMAT_A2B10G10R10_USCALED_PACK32,
+	VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
+	VK_FORMAT_A2B10G10R10_UINT_PACK32,
+	VK_FORMAT_A2B10G10R10_SINT_PACK32,
+	VK_FORMAT_R16_UNORM,
+	VK_FORMAT_R16_SNORM,
+	VK_FORMAT_R16_USCALED,
+	VK_FORMAT_R16_SSCALED,
+	VK_FORMAT_R16_UINT,
+	VK_FORMAT_R16_SINT,
+	VK_FORMAT_R16_SFLOAT,
+	VK_FORMAT_R16G16_UNORM,
+	VK_FORMAT_R16G16_SNORM,
+	VK_FORMAT_R16G16_USCALED,
+	VK_FORMAT_R16G16_SSCALED,
+	VK_FORMAT_R16G16_UINT,
+	VK_FORMAT_R16G16_SINT,
+	VK_FORMAT_R16G16_SFLOAT,
+	VK_FORMAT_R16G16B16_UNORM,
+	VK_FORMAT_R16G16B16_SNORM,
+	VK_FORMAT_R16G16B16_USCALED,
+	VK_FORMAT_R16G16B16_SSCALED,
+	VK_FORMAT_R16G16B16_UINT,
+	VK_FORMAT_R16G16B16_SINT,
+	VK_FORMAT_R16G16B16_SFLOAT,
+	VK_FORMAT_R16G16B16A16_UNORM,
+	VK_FORMAT_R16G16B16A16_SNORM,
+	VK_FORMAT_R16G16B16A16_USCALED,
+	VK_FORMAT_R16G16B16A16_SSCALED,
+	VK_FORMAT_R16G16B16A16_UINT,
+	VK_FORMAT_R16G16B16A16_SINT,
+	VK_FORMAT_R16G16B16A16_SFLOAT,
+	VK_FORMAT_R32_UINT,
+	VK_FORMAT_R32_SINT,
+	VK_FORMAT_R32_SFLOAT,
+	VK_FORMAT_R32G32_UINT,
+	VK_FORMAT_R32G32_SINT,
+	VK_FORMAT_R32G32_SFLOAT,
+	VK_FORMAT_R32G32B32_UINT,
+	VK_FORMAT_R32G32B32_SINT,
+	VK_FORMAT_R32G32B32_SFLOAT,
+	VK_FORMAT_R32G32B32A32_UINT,
+	VK_FORMAT_R32G32B32A32_SINT,
+	VK_FORMAT_R32G32B32A32_SFLOAT,
+	VK_FORMAT_R64_UINT,
+	VK_FORMAT_R64_SINT,
+	VK_FORMAT_R64_SFLOAT,
+	VK_FORMAT_R64G64_UINT,
+	VK_FORMAT_R64G64_SINT,
+	VK_FORMAT_R64G64_SFLOAT,
+	VK_FORMAT_R64G64B64_UINT,
+	VK_FORMAT_R64G64B64_SINT,
+	VK_FORMAT_R64G64B64_SFLOAT,
+	VK_FORMAT_R64G64B64A64_UINT,
+	VK_FORMAT_R64G64B64A64_SINT,
+	VK_FORMAT_R64G64B64A64_SFLOAT,
+	VK_FORMAT_B10G11R11_UFLOAT_PACK32,
+	VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
+	VK_FORMAT_D16_UNORM,
+	VK_FORMAT_X8_D24_UNORM_PACK32,
+	VK_FORMAT_D32_SFLOAT,
+	VK_FORMAT_S8_UINT,
+	VK_FORMAT_D16_UNORM_S8_UINT,
+	VK_FORMAT_D24_UNORM_S8_UINT,
+	VK_FORMAT_D32_SFLOAT_S8_UINT,
+	VK_FORMAT_BC1_RGB_UNORM_BLOCK,
+	VK_FORMAT_BC1_RGB_SRGB_BLOCK,
+	VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+	VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
+	VK_FORMAT_BC2_UNORM_BLOCK,
+	VK_FORMAT_BC2_SRGB_BLOCK,
+	VK_FORMAT_BC3_UNORM_BLOCK,
+	VK_FORMAT_BC3_SRGB_BLOCK,
+	VK_FORMAT_BC4_UNORM_BLOCK,
+	VK_FORMAT_BC4_SNORM_BLOCK,
+	VK_FORMAT_BC5_UNORM_BLOCK,
+	VK_FORMAT_BC5_SNORM_BLOCK,
+	VK_FORMAT_BC6H_UFLOAT_BLOCK,
+	VK_FORMAT_BC6H_SFLOAT_BLOCK,
+	VK_FORMAT_BC7_UNORM_BLOCK,
+	VK_FORMAT_BC7_SRGB_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
+	VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
+	VK_FORMAT_EAC_R11_UNORM_BLOCK,
+	VK_FORMAT_EAC_R11_SNORM_BLOCK,
+	VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
+	VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
+	VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
+	VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
+	VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
+	VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
+	VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
+	VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
+	VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
+	VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
+	VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
+	VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
+	VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
+	VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
+	VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
+	VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
+	VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
+	VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
+	VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
+	VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
+	VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
+	VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
+	VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
+	VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
+	VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
+	VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
+	VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
+	VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
+	VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
+	VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
+	VK_FORMAT_G8B8G8R8_422_UNORM,
+	VK_FORMAT_B8G8R8G8_422_UNORM,
+	VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
+	VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+	VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
+	VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
+	VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
+	VK_FORMAT_R10X6_UNORM_PACK16,
+	VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
+	VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+	VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
+	VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
+	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
+	VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
+	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
+	VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
+	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
+	VK_FORMAT_R12X4_UNORM_PACK16,
+	VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
+	VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
+	VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
+	VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
+	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
+	VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
+	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
+	VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
+	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
+	VK_FORMAT_G16B16G16R16_422_UNORM,
+	VK_FORMAT_B16G16R16G16_422_UNORM,
+	VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
+	VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
+	VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
+	VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
+	VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
+};
+
+// RDD::CompareOperator == VkCompareOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_NEVER, VK_COMPARE_OP_NEVER));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_LESS, VK_COMPARE_OP_LESS));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_EQUAL, VK_COMPARE_OP_EQUAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_LESS_OR_EQUAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_GREATER, VK_COMPARE_OP_GREATER));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_NOT_EQUAL, VK_COMPARE_OP_NOT_EQUAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_GREATER_OR_EQUAL, VK_COMPARE_OP_GREATER_OR_EQUAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_ALWAYS, VK_COMPARE_OP_ALWAYS));
+
+static_assert(ARRAYS_COMPATIBLE_FIELDWISE(Rect2i, VkRect2D));
+
+/****************/
+/**** MEMORY ****/
+/****************/
+
+static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
+
+VmaPool RenderingDeviceDriverVulkan::_find_or_create_small_allocs_pool(uint32_t p_mem_type_index) {
+	if (small_allocs_pools.has(p_mem_type_index)) {
+		return small_allocs_pools[p_mem_type_index];
+	}
+
+	print_verbose("Creating VMA small objects pool for memory type index " + itos(p_mem_type_index));
+
+	VmaPoolCreateInfo pci = {};
+	pci.memoryTypeIndex = p_mem_type_index;
+	pci.flags = 0;
+	pci.blockSize = 0;
+	pci.minBlockCount = 0;
+	pci.maxBlockCount = SIZE_MAX;
+	pci.priority = 0.5f;
+	pci.minAllocationAlignment = 0;
+	pci.pMemoryAllocateNext = nullptr;
+	VmaPool pool = VK_NULL_HANDLE;
+	VkResult res = vmaCreatePool(allocator, &pci, &pool);
+	small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time.
+	ERR_FAIL_COND_V_MSG(res, pool, "vmaCreatePool failed with error " + itos(res) + ".");
+
+	return pool;
+}
+
+/*****************/
+/**** BUFFERS ****/
+/*****************/
+
+// RDD::BufferUsageBits == VkBufferUsageFlagBits.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_TRANSFER_FROM_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_TRANSFER_TO_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_TEXEL_BIT, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_UNIFORM_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_STORAGE_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_INDEX_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_VERTEX_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BUFFER_USAGE_INDIRECT_BIT, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT));
+
+RDD::BufferID RenderingDeviceDriverVulkan::buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) {
+	VkBufferCreateInfo create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+	create_info.size = p_size;
+	create_info.usage = p_usage;
+	create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+	VmaAllocationCreateInfo alloc_create_info = {};
+	switch (p_allocation_type) {
+		case MEMORY_ALLOCATION_TYPE_CPU: {
+			bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT);
+			bool is_dst = p_usage.has_flag(BUFFER_USAGE_TRANSFER_TO_BIT);
+			if (is_src && !is_dst) {
+				// Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM.
+				alloc_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
+			}
+			if (is_dst && !is_src) {
+				// Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads.
+				alloc_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
+			}
+			alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
+			alloc_create_info.requiredFlags = (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+		} break;
+		case MEMORY_ALLOCATION_TYPE_GPU: {
+			alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
+			if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
+				uint32_t mem_type_index = 0;
+				vmaFindMemoryTypeIndexForBufferInfo(allocator, &create_info, &alloc_create_info, &mem_type_index);
+				alloc_create_info.pool = _find_or_create_small_allocs_pool(mem_type_index);
+			}
+		} break;
+	}
+
+	VkBuffer vk_buffer = VK_NULL_HANDLE;
+	VmaAllocation allocation = nullptr;
+	VmaAllocationInfo alloc_info = {};
+	VkResult err = vmaCreateBuffer(allocator, &create_info, &alloc_create_info, &vk_buffer, &allocation, &alloc_info);
+	ERR_FAIL_COND_V_MSG(err, BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + ".");
+
+	// Bookkeep.
+
+	BufferInfo *buf_info = VersatileResource::allocate<BufferInfo>(resources_allocator);
+	buf_info->vk_buffer = vk_buffer;
+	buf_info->allocation.handle = allocation;
+	buf_info->allocation.size = alloc_info.size;
+	buf_info->size = p_size;
+
+	return BufferID(buf_info);
+}
+
+bool RenderingDeviceDriverVulkan::buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) {
+	BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
+
+	DEV_ASSERT(!buf_info->vk_view);
+
+	VkBufferViewCreateInfo view_create_info = {};
+	view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
+	view_create_info.buffer = buf_info->vk_buffer;
+	view_create_info.format = RD_TO_VK_FORMAT[p_format];
+	view_create_info.range = buf_info->allocation.size;
+
+	VkResult res = vkCreateBufferView(vk_device, &view_create_info, nullptr, &buf_info->vk_view);
+	ERR_FAIL_COND_V_MSG(res, false, "Unable to create buffer view, error " + itos(res) + ".");
+
+	return true;
+}
+
+void RenderingDeviceDriverVulkan::buffer_free(BufferID p_buffer) {
+	BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
+	if (buf_info->vk_view) {
+		vkDestroyBufferView(vk_device, buf_info->vk_view, nullptr);
+	}
+	vmaDestroyBuffer(allocator, buf_info->vk_buffer, buf_info->allocation.handle);
+	VersatileResource::free(resources_allocator, buf_info);
+}
+
+uint64_t RenderingDeviceDriverVulkan::buffer_get_allocation_size(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	return buf_info->allocation.size;
+}
+
+uint8_t *RenderingDeviceDriverVulkan::buffer_map(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	void *data_ptr = nullptr;
+	VkResult err = vmaMapMemory(allocator, buf_info->allocation.handle, &data_ptr);
+	ERR_FAIL_COND_V_MSG(err, nullptr, "vmaMapMemory failed with error " + itos(err) + ".");
+	return (uint8_t *)data_ptr;
+}
+
+void RenderingDeviceDriverVulkan::buffer_unmap(BufferID p_buffer) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	vmaUnmapMemory(allocator, buf_info->allocation.handle);
+}
+
+/*****************/
+/**** TEXTURE ****/
+/*****************/
+
+static const VkImageType RD_TEX_TYPE_TO_VK_IMG_TYPE[RDD::TEXTURE_TYPE_MAX] = {
+	VK_IMAGE_TYPE_1D,
+	VK_IMAGE_TYPE_2D,
+	VK_IMAGE_TYPE_3D,
+	VK_IMAGE_TYPE_2D,
+	VK_IMAGE_TYPE_1D,
+	VK_IMAGE_TYPE_2D,
+	VK_IMAGE_TYPE_2D,
+};
+
+static const VkSampleCountFlagBits RD_TO_VK_SAMPLE_COUNT[RDD::TEXTURE_SAMPLES_MAX] = {
+	VK_SAMPLE_COUNT_1_BIT,
+	VK_SAMPLE_COUNT_2_BIT,
+	VK_SAMPLE_COUNT_4_BIT,
+	VK_SAMPLE_COUNT_8_BIT,
+	VK_SAMPLE_COUNT_16_BIT,
+	VK_SAMPLE_COUNT_32_BIT,
+	VK_SAMPLE_COUNT_64_BIT,
+};
+
+// RDD::TextureType == VkImageViewType.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_1D, VK_IMAGE_VIEW_TYPE_1D));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_2D, VK_IMAGE_VIEW_TYPE_2D));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_3D, VK_IMAGE_VIEW_TYPE_3D));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_CUBE, VK_IMAGE_VIEW_TYPE_CUBE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_1D_ARRAY));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_2D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_TYPE_CUBE_ARRAY, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY));
+
+// RDD::TextureSwizzle == VkComponentSwizzle.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_B, VK_COMPONENT_SWIZZLE_B));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A));
+
+// RDD::TextureLayout == VkImageLayout.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_PREINITIALIZED));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR));
+
+// RDD::TextureAspectBits == VkImageAspectFlagBits.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_DEPTH_BIT, VK_IMAGE_ASPECT_DEPTH_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_STENCIL_BIT, VK_IMAGE_ASPECT_STENCIL_BIT));
+
+VkSampleCountFlagBits RenderingDeviceDriverVulkan::_ensure_supported_sample_count(TextureSamples p_requested_sample_count) {
+	VkSampleCountFlags sample_count_flags = (context->get_device_limits().framebufferColorSampleCounts & limits.framebufferDepthSampleCounts);
+
+	if ((sample_count_flags & RD_TO_VK_SAMPLE_COUNT[p_requested_sample_count])) {
+		// The requested sample count is supported.
+		return RD_TO_VK_SAMPLE_COUNT[p_requested_sample_count];
+	} else {
+		// Find the closest lower supported sample count.
+		VkSampleCountFlagBits sample_count = RD_TO_VK_SAMPLE_COUNT[p_requested_sample_count];
+		while (sample_count > VK_SAMPLE_COUNT_1_BIT) {
+			if (sample_count_flags & sample_count) {
+				return sample_count;
+			}
+			sample_count = (VkSampleCountFlagBits)(sample_count >> 1);
+		}
+	}
+	return VK_SAMPLE_COUNT_1_BIT;
+}
+
+RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view) {
+	VkImageCreateInfo create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+
+	if (p_format.shareable_formats.size()) {
+		create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+		if (context->is_device_extension_enabled(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME)) {
+			VkFormat *vk_allowed_formats = ALLOCA_ARRAY(VkFormat, p_format.shareable_formats.size());
+			for (int i = 0; i < p_format.shareable_formats.size(); i++) {
+				vk_allowed_formats[i] = RD_TO_VK_FORMAT[p_format.shareable_formats[i]];
+			}
+
+			VkImageFormatListCreateInfoKHR *format_list_create_info = ALLOCA_SINGLE(VkImageFormatListCreateInfoKHR);
+			*format_list_create_info = {};
+			format_list_create_info->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+			format_list_create_info->viewFormatCount = p_format.shareable_formats.size();
+			format_list_create_info->pViewFormats = vk_allowed_formats;
+
+			create_info.pNext = format_list_create_info;
+		}
+	}
+
+	if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) {
+		create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+	}
+	/*if (p_format.texture_type == TEXTURE_TYPE_2D || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY) {
+		create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
+	}*/
+
+	create_info.imageType = RD_TEX_TYPE_TO_VK_IMG_TYPE[p_format.texture_type];
+
+	create_info.format = RD_TO_VK_FORMAT[p_format.format];
+
+	create_info.extent.width = p_format.width;
+	create_info.extent.height = p_format.height;
+	create_info.extent.depth = p_format.depth;
+
+	create_info.mipLevels = p_format.mipmaps;
+	create_info.arrayLayers = p_format.array_layers;
+
+	create_info.samples = _ensure_supported_sample_count(p_format.samples);
+	create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+
+	// Usage.
+	if ((p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+	}
+	if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT)) {
+		create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+	}
+
+	create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+	create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+	// Allocate memory.
+
+	uint32_t width = 0, height = 0;
+	uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
+
+	VmaAllocationCreateInfo alloc_create_info = {};
+	alloc_create_info.flags = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0;
+	alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
+	if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
+		uint32_t mem_type_index = 0;
+		vmaFindMemoryTypeIndexForImageInfo(allocator, &create_info, &alloc_create_info, &mem_type_index);
+		alloc_create_info.pool = _find_or_create_small_allocs_pool(mem_type_index);
+	}
+
+	// Create.
+
+	VkImage vk_image = VK_NULL_HANDLE;
+	VmaAllocation allocation = nullptr;
+	VmaAllocationInfo alloc_info = {};
+	VkResult err = vmaCreateImage(allocator, &create_info, &alloc_create_info, &vk_image, &allocation, &alloc_info);
+	ERR_FAIL_COND_V_MSG(err, TextureID(), "vmaCreateImage failed with error " + itos(err) + ".");
+
+	// Create view.
+
+	VkImageViewCreateInfo image_view_create_info = {};
+	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+	image_view_create_info.image = vk_image;
+	image_view_create_info.viewType = (VkImageViewType)p_format.texture_type;
+	image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
+	image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
+	image_view_create_info.components.g = (VkComponentSwizzle)p_view.swizzle_g;
+	image_view_create_info.components.b = (VkComponentSwizzle)p_view.swizzle_b;
+	image_view_create_info.components.a = (VkComponentSwizzle)p_view.swizzle_a;
+	image_view_create_info.subresourceRange.levelCount = create_info.mipLevels;
+	image_view_create_info.subresourceRange.layerCount = create_info.arrayLayers;
+	if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+	} else {
+		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	}
+
+	VkImageView vk_image_view = VK_NULL_HANDLE;
+	err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &vk_image_view);
+	if (err) {
+		vmaDestroyImage(allocator, vk_image, allocation);
+		ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + ".");
+	}
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	tex_info->vk_view = vk_image_view;
+	tex_info->rd_format = p_format.format;
+	tex_info->vk_create_info = create_info;
+	tex_info->vk_view_create_info = image_view_create_info;
+	tex_info->allocation.handle = allocation;
+	vmaGetAllocationInfo(allocator, tex_info->allocation.handle, &tex_info->allocation.info);
+
+	return TextureID(tex_info);
+}
+
+RDD::TextureID RenderingDeviceDriverVulkan::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) {
+	VkImage vk_image = (VkImage)p_native_texture;
+
+	// We only need to create a view into the already existing natively-provided texture.
+
+	VkImageViewCreateInfo image_view_create_info = {};
+	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+	image_view_create_info.image = vk_image;
+	image_view_create_info.viewType = (VkImageViewType)p_type;
+	image_view_create_info.format = RD_TO_VK_FORMAT[p_format];
+	image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_R;
+	image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_G;
+	image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_B;
+	image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_A;
+	image_view_create_info.subresourceRange.levelCount = 1;
+	image_view_create_info.subresourceRange.layerCount = p_array_layers;
+	image_view_create_info.subresourceRange.aspectMask = p_depth_stencil ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
+
+	VkImageView vk_image_view = VK_NULL_HANDLE;
+	VkResult err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &vk_image_view);
+	if (err) {
+		ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + ".");
+	}
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	tex_info->vk_view = vk_image_view;
+	tex_info->rd_format = p_format;
+	tex_info->vk_view_create_info = image_view_create_info;
+
+	return TextureID(tex_info);
+}
+
+RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
+	const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+#endif
+
+	VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
+	image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
+	image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
+	image_view_create_info.components.g = (VkComponentSwizzle)p_view.swizzle_g;
+	image_view_create_info.components.b = (VkComponentSwizzle)p_view.swizzle_b;
+	image_view_create_info.components.a = (VkComponentSwizzle)p_view.swizzle_a;
+
+	if (context->is_device_extension_enabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME)) {
+		// May need to make VK_KHR_maintenance2 mandatory and thus has Vulkan 1.1 be our minimum supported version
+		// if we require setting this information. Vulkan 1.0 may simply not care.
+		if (image_view_create_info.format != owner_tex_info->vk_view_create_info.format) {
+			VkImageViewUsageCreateInfo *usage_info = ALLOCA_SINGLE(VkImageViewUsageCreateInfo);
+			*usage_info = {};
+			usage_info->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
+			usage_info->usage = owner_tex_info->vk_create_info.usage;
+
+			// Certain features may not be available for the format of the view.
+			{
+				VkFormatProperties properties = {};
+				vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), RD_TO_VK_FORMAT[p_view.format], &properties);
+				const VkFormatFeatureFlags &supported_flags = owner_tex_info->vk_create_info.tiling == VK_IMAGE_TILING_LINEAR ? properties.linearTilingFeatures : properties.optimalTilingFeatures;
+				if ((usage_info->usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(supported_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
+					usage_info->usage &= ~VK_IMAGE_USAGE_STORAGE_BIT;
+				}
+				if ((usage_info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(supported_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
+					usage_info->usage &= ~VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+				}
+			}
+
+			image_view_create_info.pNext = usage_info;
+		}
+	}
+
+	VkImageView new_vk_image_view = VK_NULL_HANDLE;
+	VkResult err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &new_vk_image_view);
+	ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + ".");
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	*tex_info = *owner_tex_info;
+	tex_info->vk_view = new_vk_image_view;
+	tex_info->vk_view_create_info = image_view_create_info;
+	tex_info->allocation = {};
+
+	return TextureID(tex_info);
+}
+
+RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
+	const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+#endif
+
+	VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
+	switch (p_slice_type) {
+		case TEXTURE_SLICE_2D: {
+			image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+		} break;
+		case TEXTURE_SLICE_3D: {
+			image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D;
+		} break;
+		case TEXTURE_SLICE_CUBEMAP: {
+			image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
+		} break;
+		case TEXTURE_SLICE_2D_ARRAY: {
+			image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+		} break;
+	}
+	image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
+	image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
+	image_view_create_info.components.g = (VkComponentSwizzle)p_view.swizzle_g;
+	image_view_create_info.components.b = (VkComponentSwizzle)p_view.swizzle_b;
+	image_view_create_info.components.a = (VkComponentSwizzle)p_view.swizzle_a;
+	image_view_create_info.subresourceRange.baseMipLevel = p_mipmap;
+	image_view_create_info.subresourceRange.levelCount = p_mipmaps;
+	image_view_create_info.subresourceRange.baseArrayLayer = p_layer;
+	image_view_create_info.subresourceRange.layerCount = p_layers;
+
+	VkImageView new_vk_image_view = VK_NULL_HANDLE;
+	VkResult err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &new_vk_image_view);
+	ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + ".");
+
+	// Bookkeep.
+
+	TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
+	*tex_info = *owner_tex_info;
+	tex_info->vk_view = new_vk_image_view;
+	tex_info->vk_view_create_info = image_view_create_info;
+	tex_info->allocation = {};
+
+	return TextureID(tex_info);
+}
+
+void RenderingDeviceDriverVulkan::texture_free(TextureID p_texture) {
+	TextureInfo *tex_info = (TextureInfo *)p_texture.id;
+	vkDestroyImageView(vk_device, tex_info->vk_view, nullptr);
+	if (tex_info->allocation.handle) {
+		vmaDestroyImage(allocator, tex_info->vk_view_create_info.image, tex_info->allocation.handle);
+	}
+	VersatileResource::free(resources_allocator, tex_info);
+}
+
+uint64_t RenderingDeviceDriverVulkan::texture_get_allocation_size(TextureID p_texture) {
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+	return tex_info->allocation.info.size;
+}
+
+void RenderingDeviceDriverVulkan::texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) {
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+
+	*r_layout = {};
+
+	if (tex_info->vk_create_info.tiling == VK_IMAGE_TILING_LINEAR) {
+		VkImageSubresource vk_subres = {};
+		vk_subres.aspectMask = (VkImageAspectFlags)(1 << p_subresource.aspect);
+		vk_subres.arrayLayer = p_subresource.layer;
+		vk_subres.mipLevel = p_subresource.mipmap;
+
+		VkSubresourceLayout vk_layout = {};
+		vkGetImageSubresourceLayout(vk_device, tex_info->vk_view_create_info.image, &vk_subres, &vk_layout);
+
+		r_layout->offset = vk_layout.offset;
+		r_layout->size = vk_layout.size;
+		r_layout->row_pitch = vk_layout.rowPitch;
+		r_layout->depth_pitch = vk_layout.depthPitch;
+		r_layout->layer_pitch = vk_layout.arrayPitch;
+	} else {
+		// Tight.
+		uint32_t w = tex_info->vk_create_info.extent.width;
+		uint32_t h = tex_info->vk_create_info.extent.height;
+		uint32_t d = tex_info->vk_create_info.extent.depth;
+		if (p_subresource.mipmap > 0) {
+			r_layout->offset = get_image_format_required_size(tex_info->rd_format, w, h, d, p_subresource.mipmap);
+		}
+		for (uint32_t i = 0; i < p_subresource.mipmap; i++) {
+			w = MAX(1u, w >> 1);
+			h = MAX(1u, h >> 1);
+			d = MAX(1u, d >> 1);
+		}
+		r_layout->size = get_image_format_required_size(tex_info->rd_format, w, h, d, 1);
+		r_layout->row_pitch = r_layout->size / (h * d);
+		r_layout->depth_pitch = r_layout->size / d;
+		r_layout->layer_pitch = r_layout->size / tex_info->vk_create_info.arrayLayers;
+	}
+}
+
+uint8_t *RenderingDeviceDriverVulkan::texture_map(TextureID p_texture, const TextureSubresource &p_subresource) {
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+
+	VkImageSubresource vk_subres = {};
+	vk_subres.aspectMask = (VkImageAspectFlags)(1 << p_subresource.aspect);
+	vk_subres.arrayLayer = p_subresource.layer;
+	vk_subres.mipLevel = p_subresource.mipmap;
+
+	VkSubresourceLayout vk_layout = {};
+	vkGetImageSubresourceLayout(vk_device, tex_info->vk_view_create_info.image, &vk_subres, &vk_layout);
+
+	void *data_ptr = nullptr;
+	VkResult err = vkMapMemory(
+			vk_device,
+			tex_info->allocation.info.deviceMemory,
+			tex_info->allocation.info.offset + vk_layout.offset,
+			vk_layout.size,
+			0,
+			&data_ptr);
+
+	vmaMapMemory(allocator, tex_info->allocation.handle, &data_ptr);
+	ERR_FAIL_COND_V_MSG(err, nullptr, "vkMapMemory failed with error " + itos(err) + ".");
+	return (uint8_t *)data_ptr;
+}
+
+void RenderingDeviceDriverVulkan::texture_unmap(TextureID p_texture) {
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+	vkUnmapMemory(vk_device, tex_info->allocation.info.deviceMemory);
+}
+
+BitField<RDD::TextureUsageBits> RenderingDeviceDriverVulkan::texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) {
+	VkFormatProperties properties = {};
+	vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), RD_TO_VK_FORMAT[p_format], &properties);
+
+	const VkFormatFeatureFlags &flags = p_cpu_readable ? properties.linearTilingFeatures : properties.optimalTilingFeatures;
+
+	// Everything supported by default makes an all-or-nothing check easier for the caller.
+	BitField<RDD::TextureUsageBits> supported = INT64_MAX;
+
+	if (!(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+		supported.clear_flag(TEXTURE_USAGE_SAMPLING_BIT);
+	}
+	if (!(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
+		supported.clear_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
+	}
+	if (!(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+		supported.clear_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+	}
+	if (!(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
+		supported.clear_flag(TEXTURE_USAGE_STORAGE_BIT);
+	}
+	if (!(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
+		supported.clear_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);
+	}
+	// Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported.
+	if (p_format != DATA_FORMAT_R8_UINT) {
+		supported.clear_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT);
+	}
+
+	return supported;
+}
+
+/*****************/
+/**** SAMPLER ****/
+/*****************/
+
+// RDD::SamplerRepeatMode == VkSamplerAddressMode.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_REPEAT_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
+
+// RDD::SamplerBorderColor == VkBorderColor.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK, VK_BORDER_COLOR_INT_TRANSPARENT_BLACK));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK, VK_BORDER_COLOR_INT_OPAQUE_BLACK));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE, VK_BORDER_COLOR_INT_OPAQUE_WHITE));
+
+RDD::SamplerID RenderingDeviceDriverVulkan::sampler_create(const SamplerState &p_state) {
+	VkSamplerCreateInfo sampler_create_info = {};
+	sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+	sampler_create_info.pNext = nullptr;
+	sampler_create_info.flags = 0;
+	sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
+	sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
+	sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
+	sampler_create_info.addressModeU = (VkSamplerAddressMode)p_state.repeat_u;
+	sampler_create_info.addressModeV = (VkSamplerAddressMode)p_state.repeat_v;
+	sampler_create_info.addressModeW = (VkSamplerAddressMode)p_state.repeat_w;
+	sampler_create_info.mipLodBias = p_state.lod_bias;
+	sampler_create_info.anisotropyEnable = p_state.use_anisotropy && context->get_physical_device_features().samplerAnisotropy;
+	sampler_create_info.maxAnisotropy = p_state.anisotropy_max;
+	sampler_create_info.compareEnable = p_state.enable_compare;
+	sampler_create_info.compareOp = (VkCompareOp)p_state.compare_op;
+	sampler_create_info.minLod = p_state.min_lod;
+	sampler_create_info.maxLod = p_state.max_lod;
+	sampler_create_info.borderColor = (VkBorderColor)p_state.border_color;
+	sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw;
+
+	VkSampler vk_sampler = VK_NULL_HANDLE;
+	VkResult res = vkCreateSampler(vk_device, &sampler_create_info, nullptr, &vk_sampler);
+	ERR_FAIL_COND_V_MSG(res, SamplerID(), "vkCreateSampler failed with error " + itos(res) + ".");
+
+	return SamplerID(vk_sampler);
+}
+
+void RenderingDeviceDriverVulkan::sampler_free(SamplerID p_sampler) {
+	vkDestroySampler(vk_device, (VkSampler)p_sampler.id, nullptr);
+}
+
+bool RenderingDeviceDriverVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) {
+	switch (p_filter) {
+		case RD::SAMPLER_FILTER_NEAREST: {
+			return true;
+		}
+		case RD::SAMPLER_FILTER_LINEAR: {
+			VkFormatProperties properties = {};
+			vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), RD_TO_VK_FORMAT[p_format], &properties);
+			return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
+		}
+	}
+	return false;
+}
+
+/**********************/
+/**** VERTEX ARRAY ****/
+/**********************/
+
+RDD::VertexFormatID RenderingDeviceDriverVulkan::vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) {
+	// Pre-bookkeep.
+	VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);
+
+	vf_info->vk_bindings.resize(p_vertex_attribs.size());
+	vf_info->vk_attributes.resize(p_vertex_attribs.size());
+	for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
+		vf_info->vk_bindings[i] = {};
+		vf_info->vk_bindings[i].binding = i;
+		vf_info->vk_bindings[i].stride = p_vertex_attribs[i].stride;
+		vf_info->vk_bindings[i].inputRate = p_vertex_attribs[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
+		vf_info->vk_attributes[i] = {};
+		vf_info->vk_attributes[i].binding = i;
+		vf_info->vk_attributes[i].location = p_vertex_attribs[i].location;
+		vf_info->vk_attributes[i].format = RD_TO_VK_FORMAT[p_vertex_attribs[i].format];
+		vf_info->vk_attributes[i].offset = p_vertex_attribs[i].offset;
+	}
+
+	vf_info->vk_create_info = {};
+	vf_info->vk_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+	vf_info->vk_create_info.vertexBindingDescriptionCount = vf_info->vk_bindings.size();
+	vf_info->vk_create_info.pVertexBindingDescriptions = vf_info->vk_bindings.ptr();
+	vf_info->vk_create_info.vertexAttributeDescriptionCount = vf_info->vk_attributes.size();
+	vf_info->vk_create_info.pVertexAttributeDescriptions = vf_info->vk_attributes.ptr();
+
+	return VertexFormatID(vf_info);
+}
+
+void RenderingDeviceDriverVulkan::vertex_format_free(VertexFormatID p_vertex_format) {
+	VertexFormatInfo *vf_info = (VertexFormatInfo *)p_vertex_format.id;
+	VersatileResource::free(resources_allocator, vf_info);
+}
+
+/******************/
+/**** BARRIERS ****/
+/******************/
+
+// RDD::PipelineStageBits == VkPipelineStageFlagBits.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
+
+// RDD::BarrierAccessBits == VkAccessFlagBits.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT, VK_ACCESS_INDIRECT_COMMAND_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_INDEX_READ_BIT, VK_ACCESS_INDEX_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT, VK_ACCESS_UNIFORM_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_READ_BIT, VK_ACCESS_HOST_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_WRITE_BIT, VK_ACCESS_HOST_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_MEMORY_READ_BIT, VK_ACCESS_MEMORY_READ_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_MEMORY_WRITE_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR));
+
+void RenderingDeviceDriverVulkan::command_pipeline_barrier(
+		CommandBufferID p_cmd_buffer,
+		BitField<PipelineStageBits> p_src_stages,
+		BitField<PipelineStageBits> p_dst_stages,
+		VectorView<MemoryBarrier> p_memory_barriers,
+		VectorView<BufferBarrier> p_buffer_barriers,
+		VectorView<TextureBarrier> p_texture_barriers) {
+	VkMemoryBarrier *vk_memory_barriers = ALLOCA_ARRAY(VkMemoryBarrier, p_memory_barriers.size());
+	for (uint32_t i = 0; i < p_memory_barriers.size(); i++) {
+		vk_memory_barriers[i] = {};
+		vk_memory_barriers[i].sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+		vk_memory_barriers[i].srcAccessMask = (VkPipelineStageFlags)p_memory_barriers[i].src_access;
+		vk_memory_barriers[i].dstAccessMask = (VkAccessFlags)p_memory_barriers[i].dst_access;
+	}
+
+	VkBufferMemoryBarrier *vk_buffer_barriers = ALLOCA_ARRAY(VkBufferMemoryBarrier, p_buffer_barriers.size());
+	for (uint32_t i = 0; i < p_buffer_barriers.size(); i++) {
+		vk_buffer_barriers[i] = {};
+		vk_buffer_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+		vk_buffer_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		vk_buffer_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		vk_buffer_barriers[i].srcAccessMask = (VkAccessFlags)p_buffer_barriers[i].src_access;
+		vk_buffer_barriers[i].dstAccessMask = (VkAccessFlags)p_buffer_barriers[i].dst_access;
+		vk_buffer_barriers[i].buffer = ((const BufferInfo *)p_buffer_barriers[i].buffer.id)->vk_buffer;
+		vk_buffer_barriers[i].offset = p_buffer_barriers[i].offset;
+		vk_buffer_barriers[i].size = p_buffer_barriers[i].size;
+	}
+
+	VkImageMemoryBarrier *vk_image_barriers = ALLOCA_ARRAY(VkImageMemoryBarrier, p_texture_barriers.size());
+	for (uint32_t i = 0; i < p_texture_barriers.size(); i++) {
+		const TextureInfo *tex_info = (const TextureInfo *)p_texture_barriers[i].texture.id;
+		vk_image_barriers[i] = {};
+		vk_image_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+		vk_image_barriers[i].srcAccessMask = (VkAccessFlags)p_texture_barriers[i].src_access;
+		vk_image_barriers[i].dstAccessMask = (VkAccessFlags)p_texture_barriers[i].dst_access;
+		vk_image_barriers[i].oldLayout = (VkImageLayout)p_texture_barriers[i].prev_layout;
+		vk_image_barriers[i].newLayout = (VkImageLayout)p_texture_barriers[i].next_layout;
+		vk_image_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		vk_image_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		vk_image_barriers[i].image = tex_info->vk_view_create_info.image;
+		vk_image_barriers[i].subresourceRange.aspectMask = (VkImageAspectFlags)p_texture_barriers[i].subresources.aspect;
+		vk_image_barriers[i].subresourceRange.baseMipLevel = p_texture_barriers[i].subresources.base_mipmap;
+		vk_image_barriers[i].subresourceRange.levelCount = p_texture_barriers[i].subresources.mipmap_count;
+		vk_image_barriers[i].subresourceRange.baseArrayLayer = p_texture_barriers[i].subresources.base_layer;
+		vk_image_barriers[i].subresourceRange.layerCount = p_texture_barriers[i].subresources.layer_count;
+	}
+
+	vkCmdPipelineBarrier(
+			(VkCommandBuffer)p_cmd_buffer.id,
+			(VkPipelineStageFlags)p_src_stages,
+			(VkPipelineStageFlags)p_dst_stages,
+			0,
+			p_memory_barriers.size(), vk_memory_barriers,
+			p_buffer_barriers.size(), vk_buffer_barriers,
+			p_texture_barriers.size(), vk_image_barriers);
+}
+
+/*************************/
+/**** COMMAND BUFFERS ****/
+/*************************/
+
+// ----- POOL -----
+
+RDD::CommandPoolID RenderingDeviceDriverVulkan::command_pool_create(CommandBufferType p_cmd_buffer_type) {
+	VkCommandPoolCreateInfo cmd_pool_info = {};
+	cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+	cmd_pool_info.queueFamilyIndex = context->get_graphics_queue_family_index();
+	cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+
+	VkCommandPool vk_cmd_pool = VK_NULL_HANDLE;
+	VkResult res = vkCreateCommandPool(vk_device, &cmd_pool_info, nullptr, &vk_cmd_pool);
+	ERR_FAIL_COND_V_MSG(res, CommandPoolID(), "vkCreateCommandPool failed with error " + itos(res) + ".");
+
+#ifdef DEBUG_ENABLED
+	if (p_cmd_buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) {
+		secondary_cmd_pools.insert(CommandPoolID(vk_cmd_pool));
+	}
+#endif
+
+	return CommandPoolID(vk_cmd_pool);
+}
+
+void RenderingDeviceDriverVulkan::command_pool_free(CommandPoolID p_cmd_pool) {
+	vkDestroyCommandPool(vk_device, (VkCommandPool)p_cmd_pool.id, nullptr);
+
+#ifdef DEBUG_ENABLED
+	secondary_cmd_pools.erase(p_cmd_pool);
+#endif
+}
+
+// ----- BUFFER -----
+
+RDD::CommandBufferID RenderingDeviceDriverVulkan::command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) {
+#ifdef DEBUG_ENABLED
+	if (p_cmd_buffer_type == COMMAND_BUFFER_TYPE_PRIMARY) {
+		ERR_FAIL_COND_V(secondary_cmd_pools.has(p_cmd_pool), CommandBufferID());
+	} else {
+		ERR_FAIL_COND_V(!secondary_cmd_pools.has(p_cmd_pool), CommandBufferID());
+	}
+#endif
+
+	VkCommandBufferAllocateInfo cmd_buf_info = {};
+	cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+	cmd_buf_info.commandPool = (VkCommandPool)p_cmd_pool.id;
+	cmd_buf_info.level = p_cmd_buffer_type == COMMAND_BUFFER_TYPE_PRIMARY ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY;
+	cmd_buf_info.commandBufferCount = 1;
+
+	VkCommandBuffer vk_cmd_buffer = VK_NULL_HANDLE;
+	VkResult err = vkAllocateCommandBuffers(vk_device, &cmd_buf_info, &vk_cmd_buffer);
+	ERR_FAIL_COND_V_MSG(err, CommandBufferID(), "vkAllocateCommandBuffers failed with error " + itos(err) + ".");
+
+	CommandBufferID cmd_buffer_id = CommandBufferID(vk_cmd_buffer);
+#ifdef DEBUG_ENABLED
+	// Erase first because Vulkan may reuse a handle.
+	secondary_cmd_buffers.erase(cmd_buffer_id);
+	if (p_cmd_buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) {
+		secondary_cmd_buffers.insert(cmd_buffer_id);
+	}
+#endif
+	return cmd_buffer_id;
+}
+
+bool RenderingDeviceDriverVulkan::command_buffer_begin(CommandBufferID p_cmd_buffer) {
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(secondary_cmd_buffers.has(p_cmd_buffer), false);
+#endif
+
+	// Reset is implicit (VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT).
+
+	VkCommandBufferBeginInfo cmd_buf_begin_info = {};
+	cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+	cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+	VkResult err = vkBeginCommandBuffer((VkCommandBuffer)p_cmd_buffer.id, &cmd_buf_begin_info);
+	ERR_FAIL_COND_V_MSG(err, false, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
+
+	return true;
+}
+
+bool RenderingDeviceDriverVulkan::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!secondary_cmd_buffers.has(p_cmd_buffer), false);
+#endif
+
+	// Reset is implicit (VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT).
+
+	VkCommandBufferInheritanceInfo inheritance_info = {};
+	inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
+	inheritance_info.renderPass = (VkRenderPass)p_render_pass.id;
+	inheritance_info.subpass = p_subpass;
+	inheritance_info.framebuffer = (VkFramebuffer)p_framebuffer.id;
+
+	VkCommandBufferBeginInfo cmd_buf_begin_info = {};
+	cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+	cmd_buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
+	cmd_buf_begin_info.pInheritanceInfo = &inheritance_info;
+
+	VkResult err = vkBeginCommandBuffer((VkCommandBuffer)p_cmd_buffer.id, &cmd_buf_begin_info);
+	ERR_FAIL_COND_V_MSG(err, false, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
+
+	return true;
+}
+
+void RenderingDeviceDriverVulkan::command_buffer_end(CommandBufferID p_cmd_buffer) {
+	vkEndCommandBuffer((VkCommandBuffer)p_cmd_buffer.id);
+}
+
+void RenderingDeviceDriverVulkan::command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) {
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND(secondary_cmd_buffers.has(p_cmd_buffer));
+	for (uint32_t i = 0; i < p_secondary_cmd_buffers.size(); i++) {
+		ERR_FAIL_COND(!secondary_cmd_buffers.has(p_secondary_cmd_buffers[i]));
+	}
+#endif
+
+	vkCmdExecuteCommands((VkCommandBuffer)p_cmd_buffer.id, p_secondary_cmd_buffers.size(), (const VkCommandBuffer *)p_secondary_cmd_buffers.ptr());
+}
+
+/*********************/
+/**** FRAMEBUFFER ****/
+/*********************/
+
+RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) {
+	VkImageView *vk_img_views = ALLOCA_ARRAY(VkImageView, p_attachments.size());
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		vk_img_views[i] = ((const TextureInfo *)p_attachments[i].id)->vk_view;
+	}
+
+	VkFramebufferCreateInfo framebuffer_create_info = {};
+	framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+	framebuffer_create_info.renderPass = (VkRenderPass)p_render_pass.id;
+	framebuffer_create_info.attachmentCount = p_attachments.size();
+	framebuffer_create_info.pAttachments = vk_img_views;
+	framebuffer_create_info.width = p_width;
+	framebuffer_create_info.height = p_height;
+	framebuffer_create_info.layers = 1;
+
+	VkFramebuffer vk_framebuffer = VK_NULL_HANDLE;
+	VkResult err = vkCreateFramebuffer(vk_device, &framebuffer_create_info, nullptr, &vk_framebuffer);
+	ERR_FAIL_COND_V_MSG(err, FramebufferID(), "vkCreateFramebuffer failed with error " + itos(err) + ".");
+
+	return FramebufferID(vk_framebuffer);
+}
+
+void RenderingDeviceDriverVulkan::framebuffer_free(FramebufferID p_framebuffer) {
+	vkDestroyFramebuffer(vk_device, (VkFramebuffer)p_framebuffer.id, nullptr);
+}
+
+/****************/
+/**** SHADER ****/
+/****************/
+
+static VkShaderStageFlagBits RD_STAGE_TO_VK_SHADER_STAGE_BITS[RDD::SHADER_STAGE_MAX] = {
+	VK_SHADER_STAGE_VERTEX_BIT,
+	VK_SHADER_STAGE_FRAGMENT_BIT,
+	VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
+	VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
+	VK_SHADER_STAGE_COMPUTE_BIT,
+};
+
+String RenderingDeviceDriverVulkan::shader_get_binary_cache_key() {
+	return "Vulkan-SV" + uitos(ShaderBinary::VERSION);
+}
+
+Vector<uint8_t> RenderingDeviceDriverVulkan::shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) {
+	ShaderReflection shader_refl;
+	if (_reflect_spirv(p_spirv, shader_refl) != OK) {
+		return Vector<uint8_t>();
+	}
+
+	ERR_FAIL_COND_V_MSG((uint32_t)shader_refl.uniform_sets.size() > limits.maxBoundDescriptorSets, Vector<uint8_t>(),
+			"Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
+
+	// Collect reflection data into binary data.
+	ShaderBinary::Data binary_data;
+	Vector<Vector<ShaderBinary::DataBinding>> uniforms; // Set bindings.
+	Vector<ShaderBinary::SpecializationConstant> specialization_constants;
+	{
+		binary_data.vertex_input_mask = shader_refl.vertex_input_mask;
+		binary_data.fragment_output_mask = shader_refl.fragment_output_mask;
+		binary_data.specialization_constants_count = shader_refl.specialization_constants.size();
+		binary_data.is_compute = shader_refl.is_compute;
+		binary_data.compute_local_size[0] = shader_refl.compute_local_size[0];
+		binary_data.compute_local_size[1] = shader_refl.compute_local_size[1];
+		binary_data.compute_local_size[2] = shader_refl.compute_local_size[2];
+		binary_data.set_count = shader_refl.uniform_sets.size();
+		binary_data.push_constant_size = shader_refl.push_constant_size;
+		for (uint32_t i = 0; i < SHADER_STAGE_MAX; i++) {
+			if (shader_refl.push_constant_stages.has_flag((ShaderStage)(1 << i))) {
+				binary_data.vk_push_constant_stages_mask |= RD_STAGE_TO_VK_SHADER_STAGE_BITS[i];
+			}
+		}
+
+		for (const Vector<ShaderUniform> &set_refl : shader_refl.uniform_sets) {
+			Vector<ShaderBinary::DataBinding> set_bindings;
+			for (const ShaderUniform &uniform_refl : set_refl) {
+				ShaderBinary::DataBinding binding;
+				binding.type = (uint32_t)uniform_refl.type;
+				binding.binding = uniform_refl.binding;
+				binding.stages = (uint32_t)uniform_refl.stages;
+				binding.length = uniform_refl.length;
+				binding.writable = (uint32_t)uniform_refl.writable;
+				set_bindings.push_back(binding);
+			}
+			uniforms.push_back(set_bindings);
+		}
+
+		for (const ShaderSpecializationConstant &refl_sc : shader_refl.specialization_constants) {
+			ShaderBinary::SpecializationConstant spec_constant;
+			spec_constant.type = (uint32_t)refl_sc.type;
+			spec_constant.constant_id = refl_sc.constant_id;
+			spec_constant.int_value = refl_sc.int_value;
+			spec_constant.stage_flags = (uint32_t)refl_sc.stages;
+			specialization_constants.push_back(spec_constant);
+		}
+	}
+
+	Vector<Vector<uint8_t>> compressed_stages;
+	Vector<uint32_t> smolv_size;
+	Vector<uint32_t> zstd_size; // If 0, zstd not used.
+
+	uint32_t stages_binary_size = 0;
+
+	bool strip_debug = false;
+
+	for (uint32_t i = 0; i < p_spirv.size(); i++) {
+		smolv::ByteArray smolv;
+		if (!smolv::Encode(p_spirv[i].spirv.ptr(), p_spirv[i].spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) {
+			ERR_FAIL_V_MSG(Vector<uint8_t>(), "Error compressing shader stage :" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]));
+		} else {
+			smolv_size.push_back(smolv.size());
+			{ // zstd.
+				Vector<uint8_t> zstd;
+				zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
+				int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
+
+				if (dst_size > 0 && (uint32_t)dst_size < smolv.size()) {
+					zstd_size.push_back(dst_size);
+					zstd.resize(dst_size);
+					compressed_stages.push_back(zstd);
+				} else {
+					Vector<uint8_t> smv;
+					smv.resize(smolv.size());
+					memcpy(smv.ptrw(), &smolv[0], smolv.size());
+					zstd_size.push_back(0); // Not using zstd.
+					compressed_stages.push_back(smv);
+				}
+			}
+		}
+		uint32_t s = compressed_stages[i].size();
+		if (s % 4 != 0) {
+			s += 4 - (s % 4);
+		}
+		stages_binary_size += s;
+	}
+
+	binary_data.specialization_constants_count = specialization_constants.size();
+	binary_data.set_count = uniforms.size();
+	binary_data.stage_count = p_spirv.size();
+
+	CharString shader_name_utf = p_shader_name.utf8();
+
+	binary_data.shader_name_len = shader_name_utf.length();
+
+	uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
+	total_size += sizeof(ShaderBinary::Data);
+
+	total_size += binary_data.shader_name_len;
+
+	if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+		total_size += 4 - (binary_data.shader_name_len % 4);
+	}
+
+	for (int i = 0; i < uniforms.size(); i++) {
+		total_size += sizeof(uint32_t);
+		total_size += uniforms[i].size() * sizeof(ShaderBinary::DataBinding);
+	}
+
+	total_size += sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size();
+
+	total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
+	total_size += stages_binary_size;
+
+	Vector<uint8_t> ret;
+	ret.resize(total_size);
+	{
+		uint32_t offset = 0;
+		uint8_t *binptr = ret.ptrw();
+		binptr[0] = 'G';
+		binptr[1] = 'S';
+		binptr[2] = 'B';
+		binptr[3] = 'D'; // Godot Shader Binary Data.
+		offset += 4;
+		encode_uint32(ShaderBinary::VERSION, binptr + offset);
+		offset += sizeof(uint32_t);
+		encode_uint32(sizeof(ShaderBinary::Data), binptr + offset);
+		offset += sizeof(uint32_t);
+		memcpy(binptr + offset, &binary_data, sizeof(ShaderBinary::Data));
+		offset += sizeof(ShaderBinary::Data);
+
+		if (binary_data.shader_name_len > 0) {
+			memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
+			offset += binary_data.shader_name_len;
+
+			if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+				offset += 4 - (binary_data.shader_name_len % 4);
+			}
+		}
+
+		for (int i = 0; i < uniforms.size(); i++) {
+			int count = uniforms[i].size();
+			encode_uint32(count, binptr + offset);
+			offset += sizeof(uint32_t);
+			if (count > 0) {
+				memcpy(binptr + offset, uniforms[i].ptr(), sizeof(ShaderBinary::DataBinding) * count);
+				offset += sizeof(ShaderBinary::DataBinding) * count;
+			}
+		}
+
+		if (specialization_constants.size()) {
+			memcpy(binptr + offset, specialization_constants.ptr(), sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size());
+			offset += sizeof(ShaderBinary::SpecializationConstant) * specialization_constants.size();
+		}
+
+		for (int i = 0; i < compressed_stages.size(); i++) {
+			encode_uint32(p_spirv[i].shader_stage, binptr + offset);
+			offset += sizeof(uint32_t);
+			encode_uint32(smolv_size[i], binptr + offset);
+			offset += sizeof(uint32_t);
+			encode_uint32(zstd_size[i], binptr + offset);
+			offset += sizeof(uint32_t);
+			memcpy(binptr + offset, compressed_stages[i].ptr(), compressed_stages[i].size());
+
+			uint32_t s = compressed_stages[i].size();
+
+			if (s % 4 != 0) {
+				s += 4 - (s % 4);
+			}
+
+			offset += s;
+		}
+
+		DEV_ASSERT(offset == (uint32_t)ret.size());
+	}
+
+	return ret;
+}
+
+RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) {
+	r_shader_desc = {}; // Driver-agnostic.
+	ShaderInfo shader_info; // Driver-specific.
+
+	const uint8_t *binptr = p_shader_binary.ptr();
+	uint32_t binsize = p_shader_binary.size();
+
+	uint32_t read_offset = 0;
+
+	// Consistency check.
+	ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(ShaderBinary::Data), ShaderID());
+	ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', ShaderID());
+
+	uint32_t bin_version = decode_uint32(binptr + 4);
+	ERR_FAIL_COND_V(bin_version != ShaderBinary::VERSION, ShaderID());
+
+	uint32_t bin_data_size = decode_uint32(binptr + 8);
+
+	const ShaderBinary::Data &binary_data = *(reinterpret_cast<const ShaderBinary::Data *>(binptr + 12));
+
+	r_shader_desc.push_constant_size = binary_data.push_constant_size;
+	shader_info.vk_push_constant_stages = binary_data.vk_push_constant_stages_mask;
+
+	r_shader_desc.vertex_input_mask = binary_data.vertex_input_mask;
+	r_shader_desc.fragment_output_mask = binary_data.fragment_output_mask;
+
+	r_shader_desc.is_compute = binary_data.is_compute;
+	r_shader_desc.compute_local_size[0] = binary_data.compute_local_size[0];
+	r_shader_desc.compute_local_size[1] = binary_data.compute_local_size[1];
+	r_shader_desc.compute_local_size[2] = binary_data.compute_local_size[2];
+
+	read_offset += sizeof(uint32_t) * 3 + bin_data_size;
+
+	if (binary_data.shader_name_len) {
+		r_name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
+		read_offset += binary_data.shader_name_len;
+		if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
+			read_offset += 4 - (binary_data.shader_name_len % 4);
+		}
+	}
+
+	Vector<Vector<VkDescriptorSetLayoutBinding>> vk_set_bindings;
+
+	r_shader_desc.uniform_sets.resize(binary_data.set_count);
+	vk_set_bindings.resize(binary_data.set_count);
+
+	for (uint32_t i = 0; i < binary_data.set_count; i++) {
+		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, ShaderID());
+		uint32_t set_count = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		const ShaderBinary::DataBinding *set_ptr = reinterpret_cast<const ShaderBinary::DataBinding *>(binptr + read_offset);
+		uint32_t set_size = set_count * sizeof(ShaderBinary::DataBinding);
+		ERR_FAIL_COND_V(read_offset + set_size >= binsize, ShaderID());
+
+		for (uint32_t j = 0; j < set_count; j++) {
+			ShaderUniform info;
+			info.type = UniformType(set_ptr[j].type);
+			info.writable = set_ptr[j].writable;
+			info.length = set_ptr[j].length;
+			info.binding = set_ptr[j].binding;
+			info.stages = set_ptr[j].stages;
+
+			VkDescriptorSetLayoutBinding layout_binding = {};
+			layout_binding.binding = set_ptr[j].binding;
+			layout_binding.descriptorCount = 1;
+			for (uint32_t k = 0; k < SHADER_STAGE_MAX; k++) {
+				if ((set_ptr[j].stages & (1 << k))) {
+					layout_binding.stageFlags |= RD_STAGE_TO_VK_SHADER_STAGE_BITS[k];
+				}
+			}
+
+			switch (info.type) {
+				case UNIFORM_TYPE_SAMPLER: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
+					layout_binding.descriptorCount = set_ptr[j].length;
+				} break;
+				case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+					layout_binding.descriptorCount = set_ptr[j].length;
+				} break;
+				case UNIFORM_TYPE_TEXTURE: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+					layout_binding.descriptorCount = set_ptr[j].length;
+				} break;
+				case UNIFORM_TYPE_IMAGE: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+					layout_binding.descriptorCount = set_ptr[j].length;
+				} break;
+				case UNIFORM_TYPE_TEXTURE_BUFFER: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+					layout_binding.descriptorCount = set_ptr[j].length;
+				} break;
+				case UNIFORM_TYPE_IMAGE_BUFFER: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+				} break;
+				case UNIFORM_TYPE_UNIFORM_BUFFER: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+				} break;
+				case UNIFORM_TYPE_STORAGE_BUFFER: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+				} break;
+				case UNIFORM_TYPE_INPUT_ATTACHMENT: {
+					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+				} break;
+				default: {
+					DEV_ASSERT(false);
+				}
+			}
+
+			r_shader_desc.uniform_sets.write[i].push_back(info);
+			vk_set_bindings.write[i].push_back(layout_binding);
+		}
+
+		read_offset += set_size;
+	}
+
+	ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(ShaderBinary::SpecializationConstant) >= binsize, ShaderID());
+
+	r_shader_desc.specialization_constants.resize(binary_data.specialization_constants_count);
+	for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
+		const ShaderBinary::SpecializationConstant &src_sc = *(reinterpret_cast<const ShaderBinary::SpecializationConstant *>(binptr + read_offset));
+		ShaderSpecializationConstant sc;
+		sc.type = PipelineSpecializationConstantType(src_sc.type);
+		sc.constant_id = src_sc.constant_id;
+		sc.int_value = src_sc.int_value;
+		sc.stages = src_sc.stage_flags;
+		r_shader_desc.specialization_constants.write[i] = sc;
+
+		read_offset += sizeof(ShaderBinary::SpecializationConstant);
+	}
+
+	struct Stage {
+		ShaderStage type = SHADER_STAGE_MAX;
+		Vector<uint8_t> spirv;
+	};
+	Vector<Stage> stages;
+
+	for (uint32_t i = 0; i < binary_data.stage_count; i++) {
+		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, ShaderID());
+		uint32_t stage = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		uint32_t smolv_size = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+		uint32_t zstd_size = decode_uint32(binptr + read_offset);
+		read_offset += sizeof(uint32_t);
+
+		uint32_t buf_size = (zstd_size > 0) ? zstd_size : smolv_size;
+
+		Vector<uint8_t> smolv;
+		const uint8_t *src_smolv = nullptr;
+
+		if (zstd_size > 0) {
+			// Decompress to smolv.
+			smolv.resize(smolv_size);
+			int dec_smolv_size = Compression::decompress(smolv.ptrw(), smolv.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
+			ERR_FAIL_COND_V(dec_smolv_size != (int32_t)smolv_size, ShaderID());
+			src_smolv = smolv.ptr();
+		} else {
+			src_smolv = binptr + read_offset;
+		}
+
+		Vector<uint8_t> spirv;
+		uint32_t spirv_size = smolv::GetDecodedBufferSize(src_smolv, smolv_size);
+		spirv.resize(spirv_size);
+		if (!smolv::Decode(src_smolv, smolv_size, spirv.ptrw(), spirv_size)) {
+			ERR_FAIL_V_MSG(ShaderID(), "Malformed smolv input uncompressing shader stage:" + String(SHADER_STAGE_NAMES[stage]));
+		}
+
+		Stage stage_entry;
+		stage_entry.type = ShaderStage(stage);
+		stage_entry.spirv = spirv;
+		stages.push_back(stage_entry);
+
+		if (buf_size % 4 != 0) {
+			buf_size += 4 - (buf_size % 4);
+		}
+
+		DEV_ASSERT(read_offset + buf_size <= binsize);
+
+		read_offset += buf_size;
+	}
+
+	DEV_ASSERT(read_offset == binsize);
+
+	// Modules.
+
+	String error_text;
+
+	for (int i = 0; i < stages.size(); i++) {
+		VkShaderModuleCreateInfo shader_module_create_info = {};
+		shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+		shader_module_create_info.codeSize = stages[i].spirv.size();
+		shader_module_create_info.pCode = (const uint32_t *)stages[i].spirv.ptr();
+
+		VkShaderModule vk_module = VK_NULL_HANDLE;
+		VkResult res = vkCreateShaderModule(vk_device, &shader_module_create_info, nullptr, &vk_module);
+		if (res) {
+			error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[stages[i].type]);
+			break;
+		}
+
+		VkPipelineShaderStageCreateInfo create_info = {};
+		create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+		create_info.stage = RD_STAGE_TO_VK_SHADER_STAGE_BITS[stages[i].type];
+		create_info.module = vk_module;
+		create_info.pName = "main";
+
+		shader_info.vk_stages_create_info.push_back(create_info);
+	}
+
+	// Descriptor sets.
+
+	if (error_text.is_empty()) {
+		DEV_ASSERT((uint32_t)vk_set_bindings.size() == binary_data.set_count);
+		for (uint32_t i = 0; i < binary_data.set_count; i++) {
+			// Empty ones are fine if they were not used according to spec (binding count will be 0).
+			VkDescriptorSetLayoutCreateInfo layout_create_info = {};
+			layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+			layout_create_info.bindingCount = vk_set_bindings[i].size();
+			layout_create_info.pBindings = vk_set_bindings[i].ptr();
+
+			VkDescriptorSetLayout layout = VK_NULL_HANDLE;
+			VkResult res = vkCreateDescriptorSetLayout(vk_device, &layout_create_info, nullptr, &layout);
+			if (res) {
+				error_text = "Error (" + itos(res) + ") creating descriptor set layout for set " + itos(i);
+				break;
+			}
+
+			shader_info.vk_descriptor_set_layouts.push_back(layout);
+		}
+	}
+
+	if (error_text.is_empty()) {
+		// Pipeline layout.
+
+		VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
+		pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+		pipeline_layout_create_info.setLayoutCount = binary_data.set_count;
+		pipeline_layout_create_info.pSetLayouts = shader_info.vk_descriptor_set_layouts.ptr();
+
+		if (binary_data.push_constant_size) {
+			VkPushConstantRange *push_constant_range = ALLOCA_SINGLE(VkPushConstantRange);
+			*push_constant_range = {};
+			push_constant_range->stageFlags = binary_data.vk_push_constant_stages_mask;
+			push_constant_range->size = binary_data.push_constant_size;
+			pipeline_layout_create_info.pushConstantRangeCount = 1;
+			pipeline_layout_create_info.pPushConstantRanges = push_constant_range;
+		}
+
+		VkResult err = vkCreatePipelineLayout(vk_device, &pipeline_layout_create_info, nullptr, &shader_info.vk_pipeline_layout);
+		if (err) {
+			error_text = "Error (" + itos(err) + ") creating pipeline layout.";
+		}
+	}
+
+	if (!error_text.is_empty()) {
+		// Clean up if failed.
+		for (uint32_t i = 0; i < shader_info.vk_stages_create_info.size(); i++) {
+			vkDestroyShaderModule(vk_device, shader_info.vk_stages_create_info[i].module, nullptr);
+		}
+		for (uint32_t i = 0; i < binary_data.set_count; i++) {
+			vkDestroyDescriptorSetLayout(vk_device, shader_info.vk_descriptor_set_layouts[i], nullptr);
+		}
+
+		ERR_FAIL_V_MSG(ShaderID(), error_text);
+	}
+
+	// Bookkeep.
+
+	ShaderInfo *shader_info_ptr = VersatileResource::allocate<ShaderInfo>(resources_allocator);
+	*shader_info_ptr = shader_info;
+	return ShaderID(shader_info_ptr);
+}
+
+void RenderingDeviceDriverVulkan::shader_free(ShaderID p_shader) {
+	ShaderInfo *shader_info = (ShaderInfo *)p_shader.id;
+
+	for (uint32_t i = 0; i < shader_info->vk_descriptor_set_layouts.size(); i++) {
+		vkDestroyDescriptorSetLayout(vk_device, shader_info->vk_descriptor_set_layouts[i], nullptr);
+	}
+
+	vkDestroyPipelineLayout(vk_device, shader_info->vk_pipeline_layout, nullptr);
+
+	for (uint32_t i = 0; i < shader_info->vk_stages_create_info.size(); i++) {
+		vkDestroyShaderModule(vk_device, shader_info->vk_stages_create_info[i].module, nullptr);
+	}
+
+	VersatileResource::free(resources_allocator, shader_info);
+}
+
+/*********************/
+/**** UNIFORM SET ****/
+/*********************/
+
+VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_find_or_create(const DescriptorSetPoolKey &p_key, DescriptorSetPools::Iterator *r_pool_sets_it) {
+	DescriptorSetPools::Iterator pool_sets_it = descriptor_set_pools.find(p_key);
+
+	if (pool_sets_it) {
+		for (KeyValue<VkDescriptorPool, uint32_t> &E : pool_sets_it->value) {
+			if (E.value < max_descriptor_sets_per_pool) {
+				*r_pool_sets_it = pool_sets_it;
+				return E.key;
+			}
+		}
+	}
+
+	// Create a new one.
+
+	// Here comes more vulkan API strangeness.
+	VkDescriptorPoolSize *vk_sizes = ALLOCA_ARRAY(VkDescriptorPoolSize, UNIFORM_TYPE_MAX);
+	uint32_t vk_sizes_count = 0;
+	{
+		VkDescriptorPoolSize *curr_vk_size = vk_sizes;
+		if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_SAMPLER;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_TEXTURE] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_IMAGE]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] || p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+			curr_vk_size->descriptorCount = (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] + p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		if (p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT]) {
+			*curr_vk_size = {};
+			curr_vk_size->type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+			curr_vk_size->descriptorCount = p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT] * max_descriptor_sets_per_pool;
+			curr_vk_size++;
+			vk_sizes_count++;
+		}
+		DEV_ASSERT(vk_sizes_count <= UNIFORM_TYPE_MAX);
+	}
+
+	VkDescriptorPoolCreateInfo descriptor_set_pool_create_info = {};
+	descriptor_set_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+	descriptor_set_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag.
+	descriptor_set_pool_create_info.maxSets = max_descriptor_sets_per_pool;
+	descriptor_set_pool_create_info.poolSizeCount = vk_sizes_count;
+	descriptor_set_pool_create_info.pPoolSizes = vk_sizes;
+
+	VkDescriptorPool vk_pool = VK_NULL_HANDLE;
+	VkResult res = vkCreateDescriptorPool(vk_device, &descriptor_set_pool_create_info, nullptr, &vk_pool);
+	if (res) {
+		ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateDescriptorPool failed with error " + itos(res) + ".");
+	}
+
+	// Bookkeep.
+
+	if (!pool_sets_it) {
+		pool_sets_it = descriptor_set_pools.insert(p_key, HashMap<VkDescriptorPool, uint32_t>());
+	}
+	HashMap<VkDescriptorPool, uint32_t> &pool_rcs = pool_sets_it->value;
+	pool_rcs.insert(vk_pool, 0);
+	*r_pool_sets_it = pool_sets_it;
+	return vk_pool;
+}
+
+void RenderingDeviceDriverVulkan::_descriptor_set_pool_unreference(DescriptorSetPools::Iterator p_pool_sets_it, VkDescriptorPool p_vk_descriptor_pool) {
+	HashMap<VkDescriptorPool, uint32_t>::Iterator pool_rcs_it = p_pool_sets_it->value.find(p_vk_descriptor_pool);
+	pool_rcs_it->value--;
+	if (pool_rcs_it->value == 0) {
+		vkDestroyDescriptorPool(vk_device, p_vk_descriptor_pool, nullptr);
+		p_pool_sets_it->value.erase(p_vk_descriptor_pool);
+		if (p_pool_sets_it->value.is_empty()) {
+			descriptor_set_pools.remove(p_pool_sets_it);
+		}
+	}
+}
+
+RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) {
+	DescriptorSetPoolKey pool_key;
+
+	VkWriteDescriptorSet *vk_writes = ALLOCA_ARRAY(VkWriteDescriptorSet, p_uniforms.size());
+	for (uint32_t i = 0; i < p_uniforms.size(); i++) {
+		const BoundUniform &uniform = p_uniforms[i];
+
+		vk_writes[i] = {};
+		vk_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+		vk_writes[i].dstBinding = uniform.binding;
+		vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; // Invalid value.
+
+		uint32_t num_descriptors = 1;
+
+		switch (uniform.type) {
+			case UNIFORM_TYPE_SAMPLER: {
+				num_descriptors = uniform.ids.size();
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].sampler = (VkSampler)uniform.ids[j].id;
+					vk_img_infos[j].imageView = VK_NULL_HANDLE;
+					vk_img_infos[j].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
+				vk_writes[i].pImageInfo = vk_img_infos;
+			} break;
+			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
+				num_descriptors = uniform.ids.size() / 2;
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].sampler = (VkSampler)uniform.ids[j * 2 + 0].id;
+					vk_img_infos[j].imageView = ((const TextureInfo *)uniform.ids[j * 2 + 1].id)->vk_view;
+					vk_img_infos[j].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+				vk_writes[i].pImageInfo = vk_img_infos;
+			} break;
+			case UNIFORM_TYPE_TEXTURE: {
+				num_descriptors = uniform.ids.size();
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].imageView = ((const TextureInfo *)uniform.ids[j].id)->vk_view;
+					vk_img_infos[j].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+				vk_writes[i].pImageInfo = vk_img_infos;
+			} break;
+			case UNIFORM_TYPE_IMAGE: {
+				num_descriptors = uniform.ids.size();
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].imageView = ((const TextureInfo *)uniform.ids[j].id)->vk_view;
+					vk_img_infos[j].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+				vk_writes[i].pImageInfo = vk_img_infos;
+			} break;
+			case UNIFORM_TYPE_TEXTURE_BUFFER: {
+				num_descriptors = uniform.ids.size();
+				VkDescriptorBufferInfo *vk_buf_infos = ALLOCA_ARRAY(VkDescriptorBufferInfo, num_descriptors);
+				VkBufferView *vk_buf_views = ALLOCA_ARRAY(VkBufferView, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					const BufferInfo *buf_info = (const BufferInfo *)uniform.ids[j].id;
+					vk_buf_infos[j] = {};
+					vk_buf_infos[j].buffer = buf_info->vk_buffer;
+					vk_buf_infos[j].range = buf_info->size;
+
+					vk_buf_views[j] = buf_info->vk_view;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+				vk_writes[i].pBufferInfo = vk_buf_infos;
+				vk_writes[i].pTexelBufferView = vk_buf_views;
+			} break;
+			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
+				num_descriptors = uniform.ids.size() / 2;
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+				VkDescriptorBufferInfo *vk_buf_infos = ALLOCA_ARRAY(VkDescriptorBufferInfo, num_descriptors);
+				VkBufferView *vk_buf_views = ALLOCA_ARRAY(VkBufferView, num_descriptors);
+
+				for (uint32_t j = 0; j < num_descriptors; j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].sampler = (VkSampler)uniform.ids[j * 2 + 0].id;
+
+					const BufferInfo *buf_info = (const BufferInfo *)uniform.ids[j * 2 + 1].id;
+					vk_buf_infos[j] = {};
+					vk_buf_infos[j].buffer = buf_info->vk_buffer;
+					vk_buf_infos[j].range = buf_info->size;
+
+					vk_buf_views[j] = buf_info->vk_view;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+				vk_writes[i].pImageInfo = vk_img_infos;
+				vk_writes[i].pBufferInfo = vk_buf_infos;
+				vk_writes[i].pTexelBufferView = vk_buf_views;
+			} break;
+			case UNIFORM_TYPE_IMAGE_BUFFER: {
+				CRASH_NOW_MSG("Unimplemented!"); // TODO.
+			} break;
+			case UNIFORM_TYPE_UNIFORM_BUFFER: {
+				const BufferInfo *buf_info = (const BufferInfo *)uniform.ids[0].id;
+				VkDescriptorBufferInfo *vk_buf_info = ALLOCA_SINGLE(VkDescriptorBufferInfo);
+				*vk_buf_info = {};
+				vk_buf_info->buffer = buf_info->vk_buffer;
+				vk_buf_info->range = buf_info->size;
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+				vk_writes[i].pBufferInfo = vk_buf_info;
+			} break;
+			case UNIFORM_TYPE_STORAGE_BUFFER: {
+				const BufferInfo *buf_info = (const BufferInfo *)uniform.ids[0].id;
+				VkDescriptorBufferInfo *vk_buf_info = ALLOCA_SINGLE(VkDescriptorBufferInfo);
+				*vk_buf_info = {};
+				vk_buf_info->buffer = buf_info->vk_buffer;
+				vk_buf_info->range = buf_info->size;
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+				vk_writes[i].pBufferInfo = vk_buf_info;
+			} break;
+			case UNIFORM_TYPE_INPUT_ATTACHMENT: {
+				num_descriptors = uniform.ids.size();
+				VkDescriptorImageInfo *vk_img_infos = ALLOCA_ARRAY(VkDescriptorImageInfo, num_descriptors);
+
+				for (uint32_t j = 0; j < uniform.ids.size(); j++) {
+					vk_img_infos[j] = {};
+					vk_img_infos[j].imageView = ((const TextureInfo *)uniform.ids[j].id)->vk_view;
+					vk_img_infos[j].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+				}
+
+				vk_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+				vk_writes[i].pImageInfo = vk_img_infos;
+			} break;
+			default: {
+				DEV_ASSERT(false);
+			}
+		}
+
+		vk_writes[i].descriptorCount = num_descriptors;
+
+		ERR_FAIL_COND_V_MSG(pool_key.uniform_type[uniform.type] == MAX_UNIFORM_POOL_ELEMENT, UniformSetID(),
+				"Uniform set reached the limit of bindings for the same type (" + itos(MAX_UNIFORM_POOL_ELEMENT) + ").");
+		pool_key.uniform_type[uniform.type] += num_descriptors;
+	}
+
+	// Need a descriptor pool.
+	DescriptorSetPools::Iterator pool_sets_it = {};
+	VkDescriptorPool vk_pool = _descriptor_set_pool_find_or_create(pool_key, &pool_sets_it);
+	DEV_ASSERT(vk_pool);
+	pool_sets_it->value[vk_pool]++;
+
+	VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {};
+	descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+	descriptor_set_allocate_info.descriptorPool = vk_pool;
+	descriptor_set_allocate_info.descriptorSetCount = 1;
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+	descriptor_set_allocate_info.pSetLayouts = &shader_info->vk_descriptor_set_layouts[p_set_index];
+
+	VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE;
+	VkResult res = vkAllocateDescriptorSets(vk_device, &descriptor_set_allocate_info, &vk_descriptor_set);
+	if (res) {
+		_descriptor_set_pool_unreference(pool_sets_it, vk_pool);
+		ERR_FAIL_V_MSG(UniformSetID(), "Cannot allocate descriptor sets, error " + itos(res) + ".");
+	}
+
+	for (uint32_t i = 0; i < p_uniforms.size(); i++) {
+		vk_writes[i].dstSet = vk_descriptor_set;
+	}
+	vkUpdateDescriptorSets(vk_device, p_uniforms.size(), vk_writes, 0, nullptr);
+
+	// Bookkeep.
+
+	UniformSetInfo *usi = VersatileResource::allocate<UniformSetInfo>(resources_allocator);
+	usi->vk_descriptor_set = vk_descriptor_set;
+	usi->vk_descriptor_pool = vk_pool;
+	usi->pool_sets_it = pool_sets_it;
+
+	return UniformSetID(usi);
+}
+
+void RenderingDeviceDriverVulkan::uniform_set_free(UniformSetID p_uniform_set) {
+	UniformSetInfo *usi = (UniformSetInfo *)p_uniform_set.id;
+	vkFreeDescriptorSets(vk_device, usi->vk_descriptor_pool, 1, &usi->vk_descriptor_set);
+
+	_descriptor_set_pool_unreference(usi->pool_sets_it, usi->vk_descriptor_pool);
+
+	VersatileResource::free(resources_allocator, usi);
+}
+
+// ----- COMMANDS -----
+
+void RenderingDeviceDriverVulkan::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+}
+
+/******************/
+/**** TRANSFER ****/
+/******************/
+
+static_assert(ARRAYS_COMPATIBLE_FIELDWISE(RDD::BufferCopyRegion, VkBufferCopy));
+
+static void _texture_subresource_range_to_vk(const RDD::TextureSubresourceRange &p_subresources, VkImageSubresourceRange *r_vk_subreources) {
+	*r_vk_subreources = {};
+	r_vk_subreources->aspectMask = (VkImageAspectFlags)p_subresources.aspect;
+	r_vk_subreources->baseMipLevel = p_subresources.base_mipmap;
+	r_vk_subreources->levelCount = p_subresources.mipmap_count;
+	r_vk_subreources->baseArrayLayer = p_subresources.base_layer;
+	r_vk_subreources->layerCount = p_subresources.layer_count;
+}
+
+static void _texture_subresource_layers_to_vk(const RDD::TextureSubresourceLayers &p_subresources, VkImageSubresourceLayers *r_vk_subreources) {
+	*r_vk_subreources = {};
+	r_vk_subreources->aspectMask = (VkImageAspectFlags)p_subresources.aspect;
+	r_vk_subreources->mipLevel = p_subresources.mipmap;
+	r_vk_subreources->baseArrayLayer = p_subresources.base_layer;
+	r_vk_subreources->layerCount = p_subresources.layer_count;
+}
+
+static void _buffer_texture_copy_region_to_vk(const RDD::BufferTextureCopyRegion &p_copy_region, VkBufferImageCopy *r_vk_copy_region) {
+	*r_vk_copy_region = {};
+	r_vk_copy_region->bufferOffset = p_copy_region.buffer_offset;
+	_texture_subresource_layers_to_vk(p_copy_region.texture_subresources, &r_vk_copy_region->imageSubresource);
+	r_vk_copy_region->imageOffset.x = p_copy_region.texture_offset.x;
+	r_vk_copy_region->imageOffset.y = p_copy_region.texture_offset.y;
+	r_vk_copy_region->imageOffset.z = p_copy_region.texture_offset.z;
+	r_vk_copy_region->imageExtent.width = p_copy_region.texture_region_size.x;
+	r_vk_copy_region->imageExtent.height = p_copy_region.texture_region_size.y;
+	r_vk_copy_region->imageExtent.depth = p_copy_region.texture_region_size.z;
+}
+
+static void _texture_copy_region_to_vk(const RDD::TextureCopyRegion &p_copy_region, VkImageCopy *r_vk_copy_region) {
+	*r_vk_copy_region = {};
+	_texture_subresource_layers_to_vk(p_copy_region.src_subresources, &r_vk_copy_region->srcSubresource);
+	r_vk_copy_region->srcOffset.x = p_copy_region.src_offset.x;
+	r_vk_copy_region->srcOffset.y = p_copy_region.src_offset.y;
+	r_vk_copy_region->srcOffset.z = p_copy_region.src_offset.z;
+	_texture_subresource_layers_to_vk(p_copy_region.dst_subresources, &r_vk_copy_region->dstSubresource);
+	r_vk_copy_region->dstOffset.x = p_copy_region.dst_offset.x;
+	r_vk_copy_region->dstOffset.y = p_copy_region.dst_offset.y;
+	r_vk_copy_region->dstOffset.z = p_copy_region.dst_offset.z;
+	r_vk_copy_region->extent.width = p_copy_region.size.x;
+	r_vk_copy_region->extent.height = p_copy_region.size.y;
+	r_vk_copy_region->extent.depth = p_copy_region.size.z;
+}
+
+void RenderingDeviceDriverVulkan::command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, p_offset, p_size, 0);
+}
+
+void RenderingDeviceDriverVulkan::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) {
+	const BufferInfo *src_buf_info = (const BufferInfo *)p_src_buffer.id;
+	const BufferInfo *dst_buf_info = (const BufferInfo *)p_dst_buffer.id;
+	vkCmdCopyBuffer((VkCommandBuffer)p_cmd_buffer.id, src_buf_info->vk_buffer, dst_buf_info->vk_buffer, p_regions.size(), (const VkBufferCopy *)p_regions.ptr());
+}
+
+void RenderingDeviceDriverVulkan::command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) {
+	VkImageCopy *vk_copy_regions = ALLOCA_ARRAY(VkImageCopy, p_regions.size());
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		_texture_copy_region_to_vk(p_regions[i], &vk_copy_regions[i]);
+	}
+
+	const TextureInfo *src_tex_info = (const TextureInfo *)p_src_texture.id;
+	const TextureInfo *dst_tex_info = (const TextureInfo *)p_dst_texture.id;
+	vkCmdCopyImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions);
+}
+
+void RenderingDeviceDriverVulkan::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
+	const TextureInfo *src_tex_info = (const TextureInfo *)p_src_texture.id;
+	const TextureInfo *dst_tex_info = (const TextureInfo *)p_dst_texture.id;
+
+	VkImageResolve vk_resolve = {};
+	vk_resolve.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	vk_resolve.srcSubresource.mipLevel = p_src_mipmap;
+	vk_resolve.srcSubresource.baseArrayLayer = p_src_layer;
+	vk_resolve.srcSubresource.layerCount = 1;
+	vk_resolve.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	vk_resolve.dstSubresource.mipLevel = p_dst_mipmap;
+	vk_resolve.dstSubresource.baseArrayLayer = p_dst_layer;
+	vk_resolve.dstSubresource.layerCount = 1;
+	vk_resolve.extent.width = MAX(1u, src_tex_info->vk_create_info.extent.width >> p_src_mipmap);
+	vk_resolve.extent.height = MAX(1u, src_tex_info->vk_create_info.extent.height >> p_src_mipmap);
+	vk_resolve.extent.depth = MAX(1u, src_tex_info->vk_create_info.extent.depth >> p_src_mipmap);
+
+	vkCmdResolveImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, 1, &vk_resolve);
+}
+
+void RenderingDeviceDriverVulkan::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {
+	VkClearColorValue vk_color = {};
+	memcpy(&vk_color.float32, p_color.components, sizeof(VkClearColorValue::float32));
+
+	VkImageSubresourceRange vk_subresources = {};
+	_texture_subresource_range_to_vk(p_subresources, &vk_subresources);
+
+	const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
+	vkCmdClearColorImage((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_texture_layout, &vk_color, 1, &vk_subresources);
+}
+
+void RenderingDeviceDriverVulkan::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {
+	VkBufferImageCopy *vk_copy_regions = ALLOCA_ARRAY(VkBufferImageCopy, p_regions.size());
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		_buffer_texture_copy_region_to_vk(p_regions[i], &vk_copy_regions[i]);
+	}
+
+	const BufferInfo *buf_info = (const BufferInfo *)p_src_buffer.id;
+	const TextureInfo *tex_info = (const TextureInfo *)p_dst_texture.id;
+	vkCmdCopyBufferToImage((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions);
+}
+
+void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) {
+	VkBufferImageCopy *vk_copy_regions = ALLOCA_ARRAY(VkBufferImageCopy, p_regions.size());
+	for (uint32_t i = 0; i < p_regions.size(); i++) {
+		_buffer_texture_copy_region_to_vk(p_regions[i], &vk_copy_regions[i]);
+	}
+
+	const TextureInfo *tex_info = (const TextureInfo *)p_src_texture.id;
+	const BufferInfo *buf_info = (const BufferInfo *)p_dst_buffer.id;
+	vkCmdCopyImageToBuffer((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, buf_info->vk_buffer, p_regions.size(), vk_copy_regions);
+}
+
+/******************/
+/**** PIPELINE ****/
+/******************/
+
+void RenderingDeviceDriverVulkan::pipeline_free(PipelineID p_pipeline) {
+	vkDestroyPipeline(vk_device, (VkPipeline)p_pipeline.id, nullptr);
+}
+
+// ----- BINDING -----
+
+void RenderingDeviceDriverVulkan::command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView<uint32_t> p_data) {
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+	vkCmdPushConstants((VkCommandBuffer)p_cmd_buffer.id, shader_info->vk_pipeline_layout, shader_info->vk_push_constant_stages, p_dst_first_index * sizeof(uint32_t), p_data.size() * sizeof(uint32_t), p_data.ptr());
+}
+
+// ----- CACHE -----
+
+int RenderingDeviceDriverVulkan::caching_instance_count = 0;
+
+bool RenderingDeviceDriverVulkan::pipeline_cache_create(const Vector<uint8_t> &p_data) {
+	if (caching_instance_count) {
+		WARN_PRINT("There's already a RenderingDeviceDriverVulkan instance doing PSO caching. Only one can at the same time. This one won't.");
+		return false;
+	}
+	caching_instance_count++;
+
+	pipelines_cache.current_size = 0;
+	pipelines_cache.buffer.resize(sizeof(PipelineCacheHeader));
+
+	// Parse.
+	{
+		if (p_data.size() <= (int)sizeof(PipelineCacheHeader)) {
+			WARN_PRINT("Invalid/corrupt pipelines cache.");
+		} else {
+			const PipelineCacheHeader *loaded_header = reinterpret_cast<const PipelineCacheHeader *>(p_data.ptr());
+			if (loaded_header->magic != 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE) {
+				WARN_PRINT("Invalid pipelines cache magic number.");
+			} else {
+				const uint8_t *loaded_buffer_start = p_data.ptr() + sizeof(PipelineCacheHeader);
+				uint32_t loaded_buffer_size = p_data.size() - sizeof(PipelineCacheHeader);
+				const PipelineCacheHeader *current_header = (PipelineCacheHeader *)pipelines_cache.buffer.ptr();
+				if (loaded_header->data_hash != hash_murmur3_buffer(loaded_buffer_start, loaded_buffer_size) ||
+						loaded_header->data_size != loaded_buffer_size ||
+						loaded_header->vendor_id != current_header->vendor_id ||
+						loaded_header->device_id != current_header->device_id ||
+						loaded_header->driver_version != current_header->driver_version ||
+						memcmp(loaded_header->uuid, current_header->uuid, VK_UUID_SIZE) != 0 ||
+						loaded_header->driver_abi != current_header->driver_abi) {
+					WARN_PRINT("Invalid pipelines cache header.");
+				} else {
+					pipelines_cache.current_size = loaded_buffer_size;
+					pipelines_cache.buffer = p_data;
+				}
+			}
+		}
+	}
+
+	// Create.
+	{
+		VkPipelineCacheCreateInfo cache_info = {};
+		cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+		if (context->get_pipeline_cache_control_support()) {
+			cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
+		}
+		cache_info.initialDataSize = pipelines_cache.buffer.size() - sizeof(PipelineCacheHeader);
+		cache_info.pInitialData = pipelines_cache.buffer.ptr() + sizeof(PipelineCacheHeader);
+
+		VkResult err = vkCreatePipelineCache(vk_device, &cache_info, nullptr, &pipelines_cache.vk_cache);
+		if (err != VK_SUCCESS) {
+			WARN_PRINT("vkCreatePipelinecache failed with error " + itos(err) + ".");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void RenderingDeviceDriverVulkan::pipeline_cache_free() {
+	DEV_ASSERT(pipelines_cache.vk_cache);
+
+	vkDestroyPipelineCache(vk_device, pipelines_cache.vk_cache, nullptr);
+
+	DEV_ASSERT(caching_instance_count > 0);
+	caching_instance_count--;
+}
+
+size_t RenderingDeviceDriverVulkan::pipeline_cache_query_size() {
+	DEV_ASSERT(pipelines_cache.vk_cache);
+
+	// FIXME:
+	// We're letting the cache grow unboundedly. We may want to set at limit and see if implementations use LRU or the like.
+	// If we do, we won't be able to assume any longer that the cache is dirty if, and only if, it has grown.
+	VkResult err = vkGetPipelineCacheData(vk_device, pipelines_cache.vk_cache, &pipelines_cache.current_size, nullptr);
+	ERR_FAIL_COND_V_MSG(err, 0, "vkGetPipelineCacheData failed with error " + itos(err) + ".");
+
+	return pipelines_cache.current_size;
+}
+
+Vector<uint8_t> RenderingDeviceDriverVulkan::pipeline_cache_serialize() {
+	DEV_ASSERT(pipelines_cache.vk_cache);
+
+	pipelines_cache.buffer.resize(pipelines_cache.current_size + sizeof(PipelineCacheHeader));
+
+	VkResult err = vkGetPipelineCacheData(vk_device, pipelines_cache.vk_cache, &pipelines_cache.current_size, pipelines_cache.buffer.ptrw() + sizeof(PipelineCacheHeader));
+	ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, Vector<uint8_t>()); // Incomplete is OK because the cache may have grown since the size was queried (unless when exiting).
+
+	// The real buffer size may now be bigger than the updated current_size.
+	// We take into account the new size but keep the buffer resized in a worst-case fashion.
+
+	PipelineCacheHeader *header = (PipelineCacheHeader *)pipelines_cache.buffer.ptrw();
+	header->data_size = pipelines_cache.current_size;
+	header->data_hash = hash_murmur3_buffer(pipelines_cache.buffer.ptr() + sizeof(PipelineCacheHeader), pipelines_cache.current_size);
+
+	return pipelines_cache.buffer;
+}
+
+/*******************/
+/**** RENDERING ****/
+/*******************/
+
+// ----- SUBPASS -----
+
+// RDD::AttachmentLoadOp == VkAttachmentLoadOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE));
+
+// RDD::AttachmentStoreOp == VkAttachmentStoreOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_STORE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE));
+
+// Assuming Vulkan and RDD's are backed by uint32_t in:
+// - VkSubpassDescription2::pPreserveAttachments and RDD::Subpass::preserve_attachments.
+// - VkRenderPassCreateInfo2KHR::pCorrelatedViewMasks and p_view_correlation_mask.
+
+static void _attachment_reference_to_vk(const RDD::AttachmentReference &p_attachment_reference, VkAttachmentReference2KHR *r_vk_attachment_reference) {
+	*r_vk_attachment_reference = {};
+	r_vk_attachment_reference->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+	r_vk_attachment_reference->attachment = p_attachment_reference.attachment;
+	r_vk_attachment_reference->layout = (VkImageLayout)p_attachment_reference.layout;
+	r_vk_attachment_reference->aspectMask = (VkImageAspectFlags)p_attachment_reference.aspect;
+}
+
+RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) {
+	// These are only used if we use multiview but we need to define them in scope.
+	const uint32_t view_mask = (1 << p_view_count) - 1;
+	const uint32_t correlation_mask = (1 << p_view_count) - 1;
+
+	VkAttachmentDescription2KHR *vk_attachments = ALLOCA_ARRAY(VkAttachmentDescription2KHR, p_attachments.size());
+	for (uint32_t i = 0; i < p_attachments.size(); i++) {
+		vk_attachments[i] = {};
+		vk_attachments[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
+		vk_attachments[i].format = RD_TO_VK_FORMAT[p_attachments[i].format];
+		vk_attachments[i].samples = _ensure_supported_sample_count(p_attachments[i].samples);
+		vk_attachments[i].loadOp = (VkAttachmentLoadOp)p_attachments[i].load_op;
+		vk_attachments[i].storeOp = (VkAttachmentStoreOp)p_attachments[i].store_op;
+		vk_attachments[i].stencilLoadOp = (VkAttachmentLoadOp)p_attachments[i].stencil_load_op;
+		vk_attachments[i].stencilStoreOp = (VkAttachmentStoreOp)p_attachments[i].stencil_store_op;
+		vk_attachments[i].initialLayout = (VkImageLayout)p_attachments[i].initial_layout;
+		vk_attachments[i].finalLayout = (VkImageLayout)p_attachments[i].final_layout;
+	}
+
+	VkSubpassDescription2KHR *vk_subpasses = ALLOCA_ARRAY(VkSubpassDescription2KHR, p_subpasses.size());
+	for (uint32_t i = 0; i < p_subpasses.size(); i++) {
+		VkAttachmentReference2KHR *vk_subpass_input_attachments = ALLOCA_ARRAY(VkAttachmentReference2KHR, p_subpasses[i].input_references.size());
+		for (uint32_t j = 0; j < p_subpasses[i].input_references.size(); j++) {
+			_attachment_reference_to_vk(p_subpasses[i].input_references[j], &vk_subpass_input_attachments[j]);
+		}
+
+		VkAttachmentReference2KHR *vk_subpass_color_attachments = ALLOCA_ARRAY(VkAttachmentReference2KHR, p_subpasses[i].color_references.size());
+		for (uint32_t j = 0; j < p_subpasses[i].color_references.size(); j++) {
+			_attachment_reference_to_vk(p_subpasses[i].color_references[j], &vk_subpass_color_attachments[j]);
+		}
+
+		VkAttachmentReference2KHR *vk_subpass_resolve_attachments = ALLOCA_ARRAY(VkAttachmentReference2KHR, p_subpasses[i].resolve_references.size());
+		for (uint32_t j = 0; j < p_subpasses[i].resolve_references.size(); j++) {
+			_attachment_reference_to_vk(p_subpasses[i].resolve_references[j], &vk_subpass_resolve_attachments[j]);
+		}
+
+		VkAttachmentReference2KHR *vk_subpass_depth_stencil_attachment = nullptr;
+		if (p_subpasses[i].depth_stencil_reference.attachment != AttachmentReference::UNUSED) {
+			vk_subpass_depth_stencil_attachment = ALLOCA_SINGLE(VkAttachmentReference2KHR);
+			_attachment_reference_to_vk(p_subpasses[i].depth_stencil_reference, vk_subpass_depth_stencil_attachment);
+		}
+
+		vk_subpasses[i] = {};
+		vk_subpasses[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
+		vk_subpasses[i].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+		vk_subpasses[i].viewMask = p_view_count == 1 ? 0 : view_mask;
+		vk_subpasses[i].inputAttachmentCount = p_subpasses[i].input_references.size();
+		vk_subpasses[i].pInputAttachments = vk_subpass_input_attachments;
+		vk_subpasses[i].colorAttachmentCount = p_subpasses[i].color_references.size();
+		vk_subpasses[i].pColorAttachments = vk_subpass_color_attachments;
+		vk_subpasses[i].pResolveAttachments = vk_subpass_resolve_attachments;
+		vk_subpasses[i].pDepthStencilAttachment = vk_subpass_depth_stencil_attachment;
+		vk_subpasses[i].preserveAttachmentCount = p_subpasses[i].preserve_attachments.size();
+		vk_subpasses[i].pPreserveAttachments = p_subpasses[i].preserve_attachments.ptr();
+
+		// VRS.
+		if (context->get_vrs_capabilities().attachment_vrs_supported && p_subpasses[i].vrs_reference.attachment != AttachmentReference::UNUSED) {
+			VkAttachmentReference2KHR *vk_subpass_vrs_attachment = ALLOCA_SINGLE(VkAttachmentReference2KHR);
+			*vk_subpass_vrs_attachment = {};
+			vk_subpass_vrs_attachment->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+			vk_subpass_vrs_attachment->attachment = p_subpasses[i].vrs_reference.attachment;
+			vk_subpass_vrs_attachment->layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
+
+			VkFragmentShadingRateAttachmentInfoKHR *vk_vrs_info = ALLOCA_SINGLE(VkFragmentShadingRateAttachmentInfoKHR);
+			*vk_vrs_info = {};
+			vk_vrs_info->sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
+			vk_vrs_info->pFragmentShadingRateAttachment = vk_subpass_vrs_attachment;
+			vk_vrs_info->shadingRateAttachmentTexelSize.width = context->get_vrs_capabilities().texel_size.x;
+			vk_vrs_info->shadingRateAttachmentTexelSize.height = context->get_vrs_capabilities().texel_size.y;
+
+			vk_subpasses[i].pNext = vk_vrs_info;
+		}
+	}
+
+	VkSubpassDependency2KHR *vk_subpass_dependencies = ALLOCA_ARRAY(VkSubpassDependency2KHR, p_subpass_dependencies.size());
+	for (uint32_t i = 0; i < p_subpass_dependencies.size(); i++) {
+		vk_subpass_dependencies[i] = {};
+		vk_subpass_dependencies[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
+		vk_subpass_dependencies[i].srcSubpass = p_subpass_dependencies[i].src_subpass;
+		vk_subpass_dependencies[i].dstSubpass = p_subpass_dependencies[i].dst_subpass;
+		vk_subpass_dependencies[i].srcStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].src_stages;
+		vk_subpass_dependencies[i].dstStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].dst_stages;
+		vk_subpass_dependencies[i].srcAccessMask = (VkAccessFlags)p_subpass_dependencies[i].src_access;
+		vk_subpass_dependencies[i].dstAccessMask = (VkAccessFlags)p_subpass_dependencies[i].dst_access;
+	}
+
+	VkRenderPassCreateInfo2KHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
+	create_info.attachmentCount = p_attachments.size();
+	create_info.pAttachments = vk_attachments;
+	create_info.subpassCount = p_subpasses.size();
+	create_info.pSubpasses = vk_subpasses;
+	create_info.dependencyCount = p_subpass_dependencies.size();
+	create_info.pDependencies = vk_subpass_dependencies;
+	create_info.correlatedViewMaskCount = p_view_count == 1 ? 0 : 1;
+	create_info.pCorrelatedViewMasks = p_view_count == 1 ? nullptr : &correlation_mask;
+
+	// Multiview.
+	if (p_view_count > 1 && !context->supports_renderpass2()) {
+		// This is only required when using vkCreateRenderPass.
+		// We add it if vkCreateRenderPass2KHR is not supported,
+		// resulting this in being passed to our vkCreateRenderPass fallback.
+
+		uint32_t *vk_view_masks = ALLOCA_ARRAY(uint32_t, p_subpasses.size());
+		for (uint32_t i = 0; i < p_subpasses.size(); i++) {
+			vk_view_masks[i] = view_mask;
+		}
+
+		VkRenderPassMultiviewCreateInfo *multiview_create_info = ALLOCA_SINGLE(VkRenderPassMultiviewCreateInfo);
+		*multiview_create_info = {};
+		multiview_create_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
+		multiview_create_info->subpassCount = p_subpasses.size();
+		multiview_create_info->pViewMasks = vk_view_masks;
+		multiview_create_info->correlationMaskCount = 1;
+		multiview_create_info->pCorrelationMasks = &correlation_mask;
+
+		create_info.pNext = multiview_create_info;
+	}
+
+	VkRenderPass vk_render_pass = VK_NULL_HANDLE;
+	VkResult res = context->vkCreateRenderPass2KHR(vk_device, &create_info, nullptr, &vk_render_pass);
+	ERR_FAIL_COND_V_MSG(res, RenderPassID(), "vkCreateRenderPass2KHR failed with error " + itos(res) + ".");
+
+	return RenderPassID(vk_render_pass);
+}
+
+void RenderingDeviceDriverVulkan::render_pass_free(RenderPassID p_render_pass) {
+	vkDestroyRenderPass(vk_device, (VkRenderPass)p_render_pass.id, nullptr);
+}
+
+// ----- COMMANDS -----
+
+static_assert(ARRAYS_COMPATIBLE_FIELDWISE(RDD::RenderPassClearValue, VkClearValue));
+
+void RenderingDeviceDriverVulkan::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) {
+	VkRenderPassBeginInfo render_pass_begin = {};
+	render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+	render_pass_begin.renderPass = (VkRenderPass)p_render_pass.id;
+	render_pass_begin.framebuffer = (VkFramebuffer)p_framebuffer.id;
+
+	render_pass_begin.renderArea.offset.x = p_rect.position.x;
+	render_pass_begin.renderArea.offset.y = p_rect.position.y;
+	render_pass_begin.renderArea.extent.width = p_rect.size.x;
+	render_pass_begin.renderArea.extent.height = p_rect.size.y;
+
+	render_pass_begin.clearValueCount = p_clear_values.size();
+	render_pass_begin.pClearValues = (const VkClearValue *)p_clear_values.ptr();
+
+	VkSubpassContents vk_subpass_contents = p_cmd_buffer_type == COMMAND_BUFFER_TYPE_PRIMARY ? VK_SUBPASS_CONTENTS_INLINE : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
+	vkCmdBeginRenderPass((VkCommandBuffer)p_cmd_buffer.id, &render_pass_begin, vk_subpass_contents);
+}
+
+void RenderingDeviceDriverVulkan::command_end_render_pass(CommandBufferID p_cmd_buffer) {
+	vkCmdEndRenderPass((VkCommandBuffer)p_cmd_buffer.id);
+}
+
+void RenderingDeviceDriverVulkan::command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) {
+	VkSubpassContents vk_subpass_contents = p_cmd_buffer_type == COMMAND_BUFFER_TYPE_PRIMARY ? VK_SUBPASS_CONTENTS_INLINE : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
+	vkCmdNextSubpass((VkCommandBuffer)p_cmd_buffer.id, vk_subpass_contents);
+}
+
+void RenderingDeviceDriverVulkan::command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) {
+	VkViewport *vk_viewports = ALLOCA_ARRAY(VkViewport, p_viewports.size());
+	for (uint32_t i = 0; i < p_viewports.size(); i++) {
+		vk_viewports[i] = {};
+		vk_viewports[i].x = p_viewports[i].position.x;
+		vk_viewports[i].y = p_viewports[i].position.y;
+		vk_viewports[i].width = p_viewports[i].size.x;
+		vk_viewports[i].height = p_viewports[i].size.y;
+		vk_viewports[i].minDepth = 0.0f;
+		vk_viewports[i].maxDepth = 1.0f;
+	}
+	vkCmdSetViewport((VkCommandBuffer)p_cmd_buffer.id, 0, p_viewports.size(), vk_viewports);
+}
+
+void RenderingDeviceDriverVulkan::command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) {
+	vkCmdSetScissor((VkCommandBuffer)p_cmd_buffer.id, 0, p_scissors.size(), (VkRect2D *)p_scissors.ptr());
+}
+
+void RenderingDeviceDriverVulkan::command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) {
+	VkClearAttachment *vk_clears = ALLOCA_ARRAY(VkClearAttachment, p_attachment_clears.size());
+	for (uint32_t i = 0; i < p_attachment_clears.size(); i++) {
+		vk_clears[i] = {};
+		memcpy(&vk_clears[i].clearValue, &p_attachment_clears[i].value, sizeof(VkClearValue));
+		vk_clears[i].colorAttachment = p_attachment_clears[i].color_attachment;
+		vk_clears[i].aspectMask = p_attachment_clears[i].aspect;
+	}
+
+	VkClearRect *vk_rects = ALLOCA_ARRAY(VkClearRect, p_rects.size());
+	for (uint32_t i = 0; i < p_rects.size(); i++) {
+		vk_rects[i] = {};
+		vk_rects[i].rect.offset.x = p_rects[i].position.x;
+		vk_rects[i].rect.offset.y = p_rects[i].position.y;
+		vk_rects[i].rect.extent.width = p_rects[i].size.x;
+		vk_rects[i].rect.extent.height = p_rects[i].size.y;
+		vk_rects[i].baseArrayLayer = 0;
+		vk_rects[i].layerCount = 1;
+	}
+
+	vkCmdClearAttachments((VkCommandBuffer)p_cmd_buffer.id, p_attachment_clears.size(), vk_clears, p_rects.size(), vk_rects);
+}
+
+void RenderingDeviceDriverVulkan::command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
+	vkCmdBindPipeline((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_BIND_POINT_GRAPHICS, (VkPipeline)p_pipeline.id);
+}
+
+void RenderingDeviceDriverVulkan::command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+	const UniformSetInfo *usi = (const UniformSetInfo *)p_uniform_set.id;
+	vkCmdBindDescriptorSets((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_BIND_POINT_GRAPHICS, shader_info->vk_pipeline_layout, p_set_index, 1, &usi->vk_descriptor_set, 0, nullptr);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) {
+	vkCmdDraw((VkCommandBuffer)p_cmd_buffer.id, p_vertex_count, p_instance_count, p_base_vertex, p_first_instance);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) {
+	vkCmdDrawIndexed((VkCommandBuffer)p_cmd_buffer.id, p_index_count, p_instance_count, p_first_index, p_vertex_offset, p_first_instance);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_indirect_buffer.id;
+	vkCmdDrawIndexedIndirect((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, p_offset, p_draw_count, p_stride);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
+	const BufferInfo *indirect_buf_info = (const BufferInfo *)p_indirect_buffer.id;
+	const BufferInfo *count_buf_info = (const BufferInfo *)p_count_buffer.id;
+	vkCmdDrawIndexedIndirectCount((VkCommandBuffer)p_cmd_buffer.id, indirect_buf_info->vk_buffer, p_offset, count_buf_info->vk_buffer, p_count_buffer_offset, p_max_draw_count, p_stride);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_indirect_buffer.id;
+	vkCmdDrawIndirect((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, p_offset, p_draw_count, p_stride);
+}
+
+void RenderingDeviceDriverVulkan::command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
+	const BufferInfo *indirect_buf_info = (const BufferInfo *)p_indirect_buffer.id;
+	const BufferInfo *count_buf_info = (const BufferInfo *)p_count_buffer.id;
+	vkCmdDrawIndirectCount((VkCommandBuffer)p_cmd_buffer.id, indirect_buf_info->vk_buffer, p_offset, count_buf_info->vk_buffer, p_count_buffer_offset, p_max_draw_count, p_stride);
+}
+
+void RenderingDeviceDriverVulkan::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) {
+	VkBuffer *vk_buffers = ALLOCA_ARRAY(VkBuffer, p_binding_count);
+	for (uint32_t i = 0; i < p_binding_count; i++) {
+		vk_buffers[i] = ((const BufferInfo *)p_buffers[i].id)->vk_buffer;
+	}
+	vkCmdBindVertexBuffers((VkCommandBuffer)p_cmd_buffer.id, 0, p_binding_count, vk_buffers, p_offsets);
+}
+
+void RenderingDeviceDriverVulkan::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
+	vkCmdBindIndexBuffer((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, p_offset, p_format == INDEX_BUFFER_FORMAT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+}
+
+void RenderingDeviceDriverVulkan::command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) {
+	vkCmdSetBlendConstants((VkCommandBuffer)p_cmd_buffer.id, p_constants.components);
+}
+
+void RenderingDeviceDriverVulkan::command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) {
+	vkCmdSetLineWidth((VkCommandBuffer)p_cmd_buffer.id, p_width);
+}
+
+// ----- PIPELINE -----
+
+static const VkPrimitiveTopology RD_TO_VK_PRIMITIVE[RDD::RENDER_PRIMITIVE_MAX] = {
+	VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+	VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
+	VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
+	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+	VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
+};
+
+// RDD::PolygonCullMode == VkCullModeFlagBits.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::POLYGON_CULL_DISABLED, VK_CULL_MODE_NONE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::POLYGON_CULL_FRONT, VK_CULL_MODE_FRONT_BIT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::POLYGON_CULL_BACK, VK_CULL_MODE_BACK_BIT));
+
+// RDD::StencilOperation == VkStencilOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_ZERO, VK_STENCIL_OP_ZERO));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_DECREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_INVERT, VK_STENCIL_OP_INVERT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_INCREMENT_AND_WRAP, VK_STENCIL_OP_INCREMENT_AND_WRAP));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::STENCIL_OP_DECREMENT_AND_WRAP, VK_STENCIL_OP_DECREMENT_AND_WRAP));
+
+// RDD::LogicOperation == VkLogicOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_CLEAR, VK_LOGIC_OP_CLEAR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_AND, VK_LOGIC_OP_AND));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_AND_REVERSE, VK_LOGIC_OP_AND_REVERSE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_COPY, VK_LOGIC_OP_COPY));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_AND_INVERTED, VK_LOGIC_OP_AND_INVERTED));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_NO_OP, VK_LOGIC_OP_NO_OP));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_XOR, VK_LOGIC_OP_XOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_OR, VK_LOGIC_OP_OR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_NOR, VK_LOGIC_OP_NOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_EQUIVALENT, VK_LOGIC_OP_EQUIVALENT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_INVERT, VK_LOGIC_OP_INVERT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_OR_REVERSE, VK_LOGIC_OP_OR_REVERSE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_COPY_INVERTED, VK_LOGIC_OP_COPY_INVERTED));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_OR_INVERTED, VK_LOGIC_OP_OR_INVERTED));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_NAND, VK_LOGIC_OP_NAND));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::LOGIC_OP_SET, VK_LOGIC_OP_SET));
+
+// RDD::BlendFactor == VkBlendFactor.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_SRC_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_DST_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_SRC_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_DST_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_CONSTANT_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_CONSTANT_ALPHA, VK_BLEND_FACTOR_CONSTANT_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_SRC_ALPHA_SATURATE, VK_BLEND_FACTOR_SRC_ALPHA_SATURATE));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_SRC1_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_SRC1_ALPHA, VK_BLEND_FACTOR_SRC1_ALPHA));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA));
+
+// RDD::BlendOperation == VkBlendOp.
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_OP_ADD, VK_BLEND_OP_ADD));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_OP_SUBTRACT, VK_BLEND_OP_SUBTRACT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_OP_REVERSE_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_OP_MINIMUM, VK_BLEND_OP_MIN));
+static_assert(ENUM_MEMBERS_EQUAL(RDD::BLEND_OP_MAXIMUM, VK_BLEND_OP_MAX));
+
+RDD::PipelineID RenderingDeviceDriverVulkan::render_pipeline_create(
+		ShaderID p_shader,
+		VertexFormatID p_vertex_format,
+		RenderPrimitive p_render_primitive,
+		PipelineRasterizationState p_rasterization_state,
+		PipelineMultisampleState p_multisample_state,
+		PipelineDepthStencilState p_depth_stencil_state,
+		PipelineColorBlendState p_blend_state,
+		VectorView<int32_t> p_color_attachments,
+		BitField<PipelineDynamicStateFlags> p_dynamic_state,
+		RenderPassID p_render_pass,
+		uint32_t p_render_subpass,
+		VectorView<PipelineSpecializationConstant> p_specialization_constants) {
+	// Vertex.
+	const VkPipelineVertexInputStateCreateInfo *vertex_input_state_create_info = nullptr;
+	if (p_vertex_format.id) {
+		const VertexFormatInfo *vf_info = (const VertexFormatInfo *)p_vertex_format.id;
+		vertex_input_state_create_info = &vf_info->vk_create_info;
+	} else {
+		VkPipelineVertexInputStateCreateInfo *null_vertex_input_state = ALLOCA_SINGLE(VkPipelineVertexInputStateCreateInfo);
+		*null_vertex_input_state = {};
+		null_vertex_input_state->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+		vertex_input_state_create_info = null_vertex_input_state;
+	}
+
+	// Input assembly.
+	VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info = {};
+	input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+	input_assembly_create_info.topology = RD_TO_VK_PRIMITIVE[p_render_primitive];
+	input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX);
+
+	// Tessellation.
+	VkPipelineTessellationStateCreateInfo tessellation_create_info = {};
+	tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+	ERR_FAIL_COND_V(limits.maxTessellationPatchSize > 0 && (p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize), PipelineID());
+	tessellation_create_info.patchControlPoints = p_rasterization_state.patch_control_points;
+
+	// Viewport.
+	VkPipelineViewportStateCreateInfo viewport_state_create_info = {};
+	viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+	viewport_state_create_info.viewportCount = 1; // If VR extensions are supported at some point, this will have to be customizable in the framebuffer format.
+	viewport_state_create_info.scissorCount = 1;
+
+	// Rasterization.
+	VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = {};
+	rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+	rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp;
+	rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives;
+	rasterization_state_create_info.polygonMode = p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
+	rasterization_state_create_info.cullMode = (PolygonCullMode)p_rasterization_state.cull_mode;
+	rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE);
+	rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enabled;
+	rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor;
+	rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp;
+	rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
+	rasterization_state_create_info.lineWidth = p_rasterization_state.line_width;
+
+	// Multisample.
+	VkPipelineMultisampleStateCreateInfo multisample_state_create_info = {};
+	multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+	multisample_state_create_info.rasterizationSamples = _ensure_supported_sample_count(p_multisample_state.sample_count);
+	multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading;
+	multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading;
+	if (p_multisample_state.sample_mask.size()) {
+		static_assert(ARRAYS_COMPATIBLE(uint32_t, VkSampleMask));
+		multisample_state_create_info.pSampleMask = p_multisample_state.sample_mask.ptr();
+	} else {
+		multisample_state_create_info.pSampleMask = nullptr;
+	}
+	multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
+	multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one;
+
+	// Depth stencil.
+
+	VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info = {};
+	depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+	depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test;
+	depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write;
+	depth_stencil_state_create_info.depthCompareOp = (VkCompareOp)p_depth_stencil_state.depth_compare_operator;
+	depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;
+	depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil;
+
+	depth_stencil_state_create_info.front.failOp = (VkStencilOp)p_depth_stencil_state.front_op.fail;
+	depth_stencil_state_create_info.front.passOp = (VkStencilOp)p_depth_stencil_state.front_op.pass;
+	depth_stencil_state_create_info.front.depthFailOp = (VkStencilOp)p_depth_stencil_state.front_op.depth_fail;
+	depth_stencil_state_create_info.front.compareOp = (VkCompareOp)p_depth_stencil_state.front_op.compare;
+	depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.front_op.compare_mask;
+	depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.front_op.write_mask;
+	depth_stencil_state_create_info.front.reference = p_depth_stencil_state.front_op.reference;
+
+	depth_stencil_state_create_info.back.failOp = (VkStencilOp)p_depth_stencil_state.back_op.fail;
+	depth_stencil_state_create_info.back.passOp = (VkStencilOp)p_depth_stencil_state.back_op.pass;
+	depth_stencil_state_create_info.back.depthFailOp = (VkStencilOp)p_depth_stencil_state.back_op.depth_fail;
+	depth_stencil_state_create_info.back.compareOp = (VkCompareOp)p_depth_stencil_state.back_op.compare;
+	depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.back_op.compare_mask;
+	depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.back_op.write_mask;
+	depth_stencil_state_create_info.back.reference = p_depth_stencil_state.back_op.reference;
+
+	depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min;
+	depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max;
+
+	// Blend state.
+
+	VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = {};
+	color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+	color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op;
+	color_blend_state_create_info.logicOp = (VkLogicOp)p_blend_state.logic_op;
+
+	VkPipelineColorBlendAttachmentState *vk_attachment_states = ALLOCA_ARRAY(VkPipelineColorBlendAttachmentState, p_color_attachments.size());
+	{
+		for (uint32_t i = 0; i < p_color_attachments.size(); i++) {
+			vk_attachment_states[i] = {};
+			if (p_color_attachments[i] != ATTACHMENT_UNUSED) {
+				vk_attachment_states[i].blendEnable = p_blend_state.attachments[i].enable_blend;
+
+				vk_attachment_states[i].srcColorBlendFactor = (VkBlendFactor)p_blend_state.attachments[i].src_color_blend_factor;
+				vk_attachment_states[i].dstColorBlendFactor = (VkBlendFactor)p_blend_state.attachments[i].dst_color_blend_factor;
+				vk_attachment_states[i].colorBlendOp = (VkBlendOp)p_blend_state.attachments[i].color_blend_op;
+
+				vk_attachment_states[i].srcAlphaBlendFactor = (VkBlendFactor)p_blend_state.attachments[i].src_alpha_blend_factor;
+				vk_attachment_states[i].dstAlphaBlendFactor = (VkBlendFactor)p_blend_state.attachments[i].dst_alpha_blend_factor;
+				vk_attachment_states[i].alphaBlendOp = (VkBlendOp)p_blend_state.attachments[i].alpha_blend_op;
+
+				if (p_blend_state.attachments[i].write_r) {
+					vk_attachment_states[i].colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
+				}
+				if (p_blend_state.attachments[i].write_g) {
+					vk_attachment_states[i].colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
+				}
+				if (p_blend_state.attachments[i].write_b) {
+					vk_attachment_states[i].colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
+				}
+				if (p_blend_state.attachments[i].write_a) {
+					vk_attachment_states[i].colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
+				}
+			}
+		}
+	}
+	color_blend_state_create_info.attachmentCount = p_color_attachments.size();
+	color_blend_state_create_info.pAttachments = vk_attachment_states;
+
+	color_blend_state_create_info.blendConstants[0] = p_blend_state.blend_constant.r;
+	color_blend_state_create_info.blendConstants[1] = p_blend_state.blend_constant.g;
+	color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b;
+	color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a;
+
+	// Dynamic state.
+
+	VkPipelineDynamicStateCreateInfo dynamic_state_create_info = {};
+	dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+
+	static const uint32_t MAX_DYN_STATE_COUNT = 9;
+	VkDynamicState *vk_dynamic_states = ALLOCA_ARRAY(VkDynamicState, MAX_DYN_STATE_COUNT);
+	uint32_t vk_dynamic_states_count = 0;
+
+	vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_VIEWPORT; // Viewport and scissor are always dynamic.
+	vk_dynamic_states_count++;
+	vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_SCISSOR;
+	vk_dynamic_states_count++;
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_LINE_WIDTH)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_LINE_WIDTH;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_DEPTH_BIAS)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_DEPTH_BIAS;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_BLEND_CONSTANTS)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_DEPTH_BOUNDS)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_DEPTH_BOUNDS;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_STENCIL_COMPARE_MASK)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_STENCIL_WRITE_MASK)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK;
+		vk_dynamic_states_count++;
+	}
+	if (p_dynamic_state.has_flag(DYNAMIC_STATE_STENCIL_REFERENCE)) {
+		vk_dynamic_states[vk_dynamic_states_count] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
+		vk_dynamic_states_count++;
+	}
+	DEV_ASSERT(vk_dynamic_states_count <= MAX_DYN_STATE_COUNT);
+
+	dynamic_state_create_info.dynamicStateCount = vk_dynamic_states_count;
+	dynamic_state_create_info.pDynamicStates = vk_dynamic_states;
+
+	// VRS.
+
+	void *graphics_pipeline_nextptr = nullptr;
+
+	if (context->get_vrs_capabilities().attachment_vrs_supported) {
+		// If VRS is used, this defines how the different VRS types are combined.
+		// combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS.
+		// combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS.
+
+		VkPipelineFragmentShadingRateStateCreateInfoKHR *vrs_create_info = ALLOCA_SINGLE(VkPipelineFragmentShadingRateStateCreateInfoKHR);
+		*vrs_create_info = {};
+		vrs_create_info->sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR;
+		vrs_create_info->fragmentSize = { 4, 4 };
+		vrs_create_info->combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter.
+		vrs_create_info->combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // Always use the outcome of attachment VRS if enabled.
+
+		graphics_pipeline_nextptr = vrs_create_info;
+	}
+
+	// Finally, pipeline create info.
+
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+
+	VkGraphicsPipelineCreateInfo pipeline_create_info = {};
+
+	pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+	pipeline_create_info.pNext = graphics_pipeline_nextptr;
+	pipeline_create_info.stageCount = shader_info->vk_stages_create_info.size();
+
+	VkPipelineShaderStageCreateInfo *vk_pipeline_stages = ALLOCA_ARRAY(VkPipelineShaderStageCreateInfo, shader_info->vk_stages_create_info.size());
+
+	for (uint32_t i = 0; i < shader_info->vk_stages_create_info.size(); i++) {
+		vk_pipeline_stages[i] = shader_info->vk_stages_create_info[i];
+
+		if (p_specialization_constants.size()) {
+			VkSpecializationMapEntry *specialization_map_entries = ALLOCA_ARRAY(VkSpecializationMapEntry, p_specialization_constants.size());
+			for (uint32_t j = 0; j < p_specialization_constants.size(); j++) {
+				specialization_map_entries[j] = {};
+				specialization_map_entries[j].constantID = p_specialization_constants[j].constant_id;
+				specialization_map_entries[j].offset = (const char *)&p_specialization_constants[j].int_value - (const char *)p_specialization_constants.ptr();
+				specialization_map_entries[j].size = sizeof(uint32_t);
+			}
+
+			VkSpecializationInfo *specialization_info = ALLOCA_SINGLE(VkSpecializationInfo);
+			*specialization_info = {};
+			specialization_info->dataSize = p_specialization_constants.size() * sizeof(PipelineSpecializationConstant);
+			specialization_info->pData = p_specialization_constants.ptr();
+			specialization_info->mapEntryCount = p_specialization_constants.size();
+			specialization_info->pMapEntries = specialization_map_entries;
+
+			vk_pipeline_stages[i].pSpecializationInfo = specialization_info;
+		}
+	}
+
+	pipeline_create_info.pStages = vk_pipeline_stages;
+	pipeline_create_info.pVertexInputState = vertex_input_state_create_info;
+	pipeline_create_info.pInputAssemblyState = &input_assembly_create_info;
+	pipeline_create_info.pTessellationState = &tessellation_create_info;
+	pipeline_create_info.pViewportState = &viewport_state_create_info;
+	pipeline_create_info.pRasterizationState = &rasterization_state_create_info;
+	pipeline_create_info.pMultisampleState = &multisample_state_create_info;
+	pipeline_create_info.pDepthStencilState = &depth_stencil_state_create_info;
+	pipeline_create_info.pColorBlendState = &color_blend_state_create_info;
+	pipeline_create_info.pDynamicState = &dynamic_state_create_info;
+	pipeline_create_info.layout = shader_info->vk_pipeline_layout;
+	pipeline_create_info.renderPass = (VkRenderPass)p_render_pass.id;
+	pipeline_create_info.subpass = p_render_subpass;
+
+	// ---
+
+	VkPipeline vk_pipeline = VK_NULL_HANDLE;
+	VkResult err = vkCreateGraphicsPipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, nullptr, &vk_pipeline);
+	ERR_FAIL_COND_V_MSG(err, PipelineID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
+
+	return PipelineID(vk_pipeline);
+}
+
+/*****************/
+/**** COMPUTE ****/
+/*****************/
+
+// ----- COMMANDS -----
+
+void RenderingDeviceDriverVulkan::command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
+	vkCmdBindPipeline((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_BIND_POINT_COMPUTE, (VkPipeline)p_pipeline.id);
+}
+
+void RenderingDeviceDriverVulkan::command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+	const UniformSetInfo *usi = (const UniformSetInfo *)p_uniform_set.id;
+	vkCmdBindDescriptorSets((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_BIND_POINT_COMPUTE, shader_info->vk_pipeline_layout, p_set_index, 1, &usi->vk_descriptor_set, 0, nullptr);
+}
+
+void RenderingDeviceDriverVulkan::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
+	vkCmdDispatch((VkCommandBuffer)p_cmd_buffer.id, p_x_groups, p_y_groups, p_z_groups);
+}
+
+void RenderingDeviceDriverVulkan::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) {
+	const BufferInfo *buf_info = (const BufferInfo *)p_indirect_buffer.id;
+	vkCmdDispatchIndirect((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, p_offset);
+}
+
+// ----- PIPELINE -----
+
+RDD::PipelineID RenderingDeviceDriverVulkan::compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {
+	const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id;
+
+	VkComputePipelineCreateInfo pipeline_create_info = {};
+	pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+	pipeline_create_info.stage = shader_info->vk_stages_create_info[0];
+	pipeline_create_info.layout = shader_info->vk_pipeline_layout;
+
+	if (p_specialization_constants.size()) {
+		VkSpecializationMapEntry *specialization_map_entries = ALLOCA_ARRAY(VkSpecializationMapEntry, p_specialization_constants.size());
+		for (uint32_t i = 0; i < p_specialization_constants.size(); i++) {
+			specialization_map_entries[i] = {};
+			specialization_map_entries[i].constantID = p_specialization_constants[i].constant_id;
+			specialization_map_entries[i].offset = (const char *)&p_specialization_constants[i].int_value - (const char *)p_specialization_constants.ptr();
+			specialization_map_entries[i].size = sizeof(uint32_t);
+		}
+
+		VkSpecializationInfo *specialization_info = ALLOCA_SINGLE(VkSpecializationInfo);
+		*specialization_info = {};
+		specialization_info->dataSize = p_specialization_constants.size() * sizeof(PipelineSpecializationConstant);
+		specialization_info->pData = p_specialization_constants.ptr();
+		specialization_info->mapEntryCount = p_specialization_constants.size();
+		specialization_info->pMapEntries = specialization_map_entries;
+
+		pipeline_create_info.stage.pSpecializationInfo = specialization_info;
+	}
+
+	VkPipeline vk_pipeline = VK_NULL_HANDLE;
+	VkResult err = vkCreateComputePipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, nullptr, &vk_pipeline);
+	ERR_FAIL_COND_V_MSG(err, PipelineID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
+
+	return PipelineID(vk_pipeline);
+}
+
+/*****************/
+/**** QUERIES ****/
+/*****************/
+
+// ----- TIMESTAMP -----
+
+RDD::QueryPoolID RenderingDeviceDriverVulkan::timestamp_query_pool_create(uint32_t p_query_count) {
+	VkQueryPoolCreateInfo query_pool_create_info = {};
+	query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+	query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
+	query_pool_create_info.queryCount = p_query_count;
+
+	VkQueryPool vk_query_pool = VK_NULL_HANDLE;
+	vkCreateQueryPool(vk_device, &query_pool_create_info, nullptr, &vk_query_pool);
+	return RDD::QueryPoolID(vk_query_pool);
+}
+
+void RenderingDeviceDriverVulkan::timestamp_query_pool_free(QueryPoolID p_pool_id) {
+	vkDestroyQueryPool(vk_device, (VkQueryPool)p_pool_id.id, nullptr);
+}
+
+void RenderingDeviceDriverVulkan::timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) {
+	vkGetQueryPoolResults(vk_device, (VkQueryPool)p_pool_id.id, 0, p_query_count, sizeof(uint64_t) * p_query_count, r_results, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
+}
+
+uint64_t RenderingDeviceDriverVulkan::timestamp_query_result_to_time(uint64_t p_result) {
+	// This sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
+	// So, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible.
+	// Need to do 128 bits fixed point multiplication to get the right value.
+
+	auto mult64to128 = [](uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
+		uint64_t u1 = (u & 0xffffffff);
+		uint64_t v1 = (v & 0xffffffff);
+		uint64_t t = (u1 * v1);
+		uint64_t w3 = (t & 0xffffffff);
+		uint64_t k = (t >> 32);
+
+		u >>= 32;
+		t = (u * v1) + k;
+		k = (t & 0xffffffff);
+		uint64_t w1 = (t >> 32);
+
+		v >>= 32;
+		t = (u1 * v) + k;
+		k = (t >> 32);
+
+		h = (u * v) + w1 + k;
+		l = (t << 32) + w3;
+	};
+
+	uint64_t shift_bits = 16;
+	uint64_t h = 0, l = 0;
+	mult64to128(p_result, uint64_t(double(context->get_device_limits().timestampPeriod) * double(1 << shift_bits)), h, l);
+	l >>= shift_bits;
+	l |= h << (64 - shift_bits);
+
+	return l;
+}
+
+void RenderingDeviceDriverVulkan::command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) {
+	vkCmdResetQueryPool((VkCommandBuffer)p_cmd_buffer.id, (VkQueryPool)p_pool_id.id, 0, p_query_count);
+}
+
+void RenderingDeviceDriverVulkan::command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) {
+	vkCmdWriteTimestamp((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, (VkQueryPool)p_pool_id.id, p_index);
+}
+
+/****************/
+/**** SCREEN ****/
+/****************/
+
+RDD::DataFormat RenderingDeviceDriverVulkan::screen_get_format() {
+	// Very hacky, but not used often per frame so I guess ok.
+	VkFormat vk_format = context->get_screen_format();
+	DataFormat format = DATA_FORMAT_MAX;
+	for (int i = 0; i < DATA_FORMAT_MAX; i++) {
+		if (vk_format == RD_TO_VK_FORMAT[i]) {
+			format = DataFormat(i);
+			break;
+		}
+	}
+	return format;
+}
+
+/********************/
+/**** SUBMISSION ****/
+/********************/
+
+void RenderingDeviceDriverVulkan::begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) {
+}
+
+void RenderingDeviceDriverVulkan::end_segment() {
+}
+
+/**************/
+/**** MISC ****/
+/**************/
+
+void RenderingDeviceDriverVulkan::set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) {
+	switch (p_type) {
+		case OBJECT_TYPE_TEXTURE: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			if (tex_info->allocation.handle) {
+				context->set_object_name(VK_OBJECT_TYPE_IMAGE, (uint64_t)tex_info->vk_view_create_info.image, p_name);
+			}
+			context->set_object_name(VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)tex_info->vk_view, p_name + " View");
+		} break;
+		case OBJECT_TYPE_SAMPLER: {
+			context->set_object_name(VK_OBJECT_TYPE_SAMPLER, p_driver_id.id, p_name);
+		} break;
+		case OBJECT_TYPE_BUFFER: {
+			const BufferInfo *buf_info = (const BufferInfo *)p_driver_id.id;
+			context->set_object_name(VK_OBJECT_TYPE_BUFFER, (uint64_t)buf_info->vk_buffer, p_name);
+			if (buf_info->vk_view) {
+				context->set_object_name(VK_OBJECT_TYPE_BUFFER_VIEW, (uint64_t)buf_info->vk_view, p_name + " View");
+			}
+		} break;
+		case OBJECT_TYPE_SHADER: {
+			const ShaderInfo *shader_info = (const ShaderInfo *)p_driver_id.id;
+			for (uint32_t i = 0; i < shader_info->vk_descriptor_set_layouts.size(); i++) {
+				context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)shader_info->vk_descriptor_set_layouts[i], p_name);
+			}
+			context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)shader_info->vk_pipeline_layout, p_name + " Pipeline Layout");
+		} break;
+		case OBJECT_TYPE_UNIFORM_SET: {
+			const UniformSetInfo *usi = (const UniformSetInfo *)p_driver_id.id;
+			context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)usi->vk_descriptor_set, p_name);
+		} break;
+		case OBJECT_TYPE_PIPELINE: {
+			context->set_object_name(VK_OBJECT_TYPE_PIPELINE, (uint64_t)p_driver_id.id, p_name);
+		} break;
+		default: {
+			DEV_ASSERT(false);
+		}
+	}
+}
+
+uint64_t RenderingDeviceDriverVulkan::get_resource_native_handle(DriverResource p_type, ID p_driver_id) {
+	switch (p_type) {
+		case DRIVER_RESOURCE_LOGICAL_DEVICE: {
+			return (uint64_t)vk_device;
+		}
+		case DRIVER_RESOURCE_PHYSICAL_DEVICE: {
+			return (uint64_t)context->get_physical_device();
+		}
+		case DRIVER_RESOURCE_TOPMOST_OBJECT: {
+			return (uint64_t)context->get_instance();
+		}
+		case DRIVER_RESOURCE_COMMAND_QUEUE: {
+			return (uint64_t)context->get_graphics_queue();
+		}
+		case DRIVER_RESOURCE_QUEUE_FAMILY: {
+			return context->get_graphics_queue_family_index();
+		}
+		case DRIVER_RESOURCE_TEXTURE: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->vk_view_create_info.image;
+		}
+		case DRIVER_RESOURCE_TEXTURE_VIEW: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->vk_view;
+		}
+		case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {
+			const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
+			return (uint64_t)tex_info->vk_view_create_info.format;
+		}
+		case DRIVER_RESOURCE_SAMPLER:
+		case DRIVER_RESOURCE_UNIFORM_SET:
+		case DRIVER_RESOURCE_BUFFER:
+		case DRIVER_RESOURCE_COMPUTE_PIPELINE:
+		case DRIVER_RESOURCE_RENDER_PIPELINE: {
+			return p_driver_id.id;
+		}
+		default: {
+			return 0;
+		}
+	}
+}
+
+uint64_t RenderingDeviceDriverVulkan::get_total_memory_used() {
+	VmaTotalStatistics stats = {};
+	vmaCalculateStatistics(allocator, &stats);
+	return stats.total.statistics.allocationBytes;
+}
+
+uint64_t RenderingDeviceDriverVulkan::limit_get(Limit p_limit) {
+	switch (p_limit) {
+		case LIMIT_MAX_BOUND_UNIFORM_SETS:
+			return limits.maxBoundDescriptorSets;
+		case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS:
+			return limits.maxColorAttachments;
+		case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET:
+			return limits.maxDescriptorSetSampledImages;
+		case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET:
+			return limits.maxDescriptorSetSamplers;
+		case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET:
+			return limits.maxDescriptorSetStorageBuffers;
+		case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET:
+			return limits.maxDescriptorSetStorageImages;
+		case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET:
+			return limits.maxDescriptorSetUniformBuffers;
+		case LIMIT_MAX_DRAW_INDEXED_INDEX:
+			return limits.maxDrawIndexedIndexValue;
+		case LIMIT_MAX_FRAMEBUFFER_HEIGHT:
+			return limits.maxFramebufferHeight;
+		case LIMIT_MAX_FRAMEBUFFER_WIDTH:
+			return limits.maxFramebufferWidth;
+		case LIMIT_MAX_TEXTURE_ARRAY_LAYERS:
+			return limits.maxImageArrayLayers;
+		case LIMIT_MAX_TEXTURE_SIZE_1D:
+			return limits.maxImageDimension1D;
+		case LIMIT_MAX_TEXTURE_SIZE_2D:
+			return limits.maxImageDimension2D;
+		case LIMIT_MAX_TEXTURE_SIZE_3D:
+			return limits.maxImageDimension3D;
+		case LIMIT_MAX_TEXTURE_SIZE_CUBE:
+			return limits.maxImageDimensionCube;
+		case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:
+			return limits.maxPerStageDescriptorSampledImages;
+		case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE:
+			return limits.maxPerStageDescriptorSamplers;
+		case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE:
+			return limits.maxPerStageDescriptorStorageBuffers;
+		case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE:
+			return limits.maxPerStageDescriptorStorageImages;
+		case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE:
+			return limits.maxPerStageDescriptorUniformBuffers;
+		case LIMIT_MAX_PUSH_CONSTANT_SIZE:
+			return limits.maxPushConstantsSize;
+		case LIMIT_MAX_UNIFORM_BUFFER_SIZE:
+			return limits.maxUniformBufferRange;
+		case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET:
+			return limits.maxVertexInputAttributeOffset;
+		case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES:
+			return limits.maxVertexInputAttributes;
+		case LIMIT_MAX_VERTEX_INPUT_BINDINGS:
+			return limits.maxVertexInputBindings;
+		case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE:
+			return limits.maxVertexInputBindingStride;
+		case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
+			return limits.minUniformBufferOffsetAlignment;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:
+			return limits.maxComputeWorkGroupCount[0];
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:
+			return limits.maxComputeWorkGroupCount[1];
+		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:
+			return limits.maxComputeWorkGroupCount[2];
+		case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS:
+			return limits.maxComputeWorkGroupInvocations;
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:
+			return limits.maxComputeWorkGroupSize[0];
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:
+			return limits.maxComputeWorkGroupSize[1];
+		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
+			return limits.maxComputeWorkGroupSize[2];
+		case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
+			return limits.maxViewportDimensions[0];
+		case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
+			return limits.maxViewportDimensions[1];
+		case LIMIT_SUBGROUP_SIZE: {
+			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.size;
+		}
+		case LIMIT_SUBGROUP_MIN_SIZE: {
+			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.min_size;
+		}
+		case LIMIT_SUBGROUP_MAX_SIZE: {
+			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.max_size;
+		}
+		case LIMIT_SUBGROUP_IN_SHADERS: {
+			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.supported_stages_flags_rd();
+		}
+		case LIMIT_SUBGROUP_OPERATIONS: {
+			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+			return subgroup_capabilities.supported_operations_flags_rd();
+		}
+		case LIMIT_VRS_TEXEL_WIDTH:
+			return context->get_vrs_capabilities().texel_size.x;
+		case LIMIT_VRS_TEXEL_HEIGHT:
+			return context->get_vrs_capabilities().texel_size.y;
+		default:
+			ERR_FAIL_V(0);
+	}
+}
+
+uint64_t RenderingDeviceDriverVulkan::api_trait_get(ApiTrait p_trait) {
+	switch (p_trait) {
+		case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT:
+			return (uint64_t)MAX((uint64_t)16, limits.optimalBufferCopyOffsetAlignment);
+		case API_TRAIT_SHADER_CHANGE_INVALIDATION:
+			return (uint64_t)SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE;
+		default:
+			return RenderingDeviceDriver::api_trait_get(p_trait);
+	}
+}
+
+bool RenderingDeviceDriverVulkan::has_feature(Features p_feature) {
+	switch (p_feature) {
+		case SUPPORTS_MULTIVIEW: {
+			MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities();
+			return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
+		} break;
+		case SUPPORTS_FSR_HALF_FLOAT: {
+			return context->get_shader_capabilities().shader_float16_is_supported && context->get_physical_device_features().shaderInt16 && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
+		} break;
+		case SUPPORTS_ATTACHMENT_VRS: {
+			VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
+			return vrs_capabilities.attachment_vrs_supported && context->get_physical_device_features().shaderStorageImageExtendedFormats;
+		} break;
+		case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: {
+			return true;
+		} break;
+		default: {
+			return false;
+		}
+	}
+}
+
+const RDD::MultiviewCapabilities &RenderingDeviceDriverVulkan::get_multiview_capabilities() {
+	return context->get_multiview_capabilities();
+}
+
+/******************/
+
+RenderingDeviceDriverVulkan::RenderingDeviceDriverVulkan(VulkanContext *p_context, VkDevice p_vk_device) :
+		context(p_context),
+		vk_device(p_vk_device) {
+	VmaAllocatorCreateInfo allocator_info = {};
+	allocator_info.physicalDevice = context->get_physical_device();
+	allocator_info.device = vk_device;
+	allocator_info.instance = context->get_instance();
+	VkResult err = vmaCreateAllocator(&allocator_info, &allocator);
+	ERR_FAIL_COND_MSG(err, "vmaCreateAllocator failed with error " + itos(err) + ".");
+
+	max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool");
+
+	VkPhysicalDeviceProperties props = {};
+	vkGetPhysicalDeviceProperties(context->get_physical_device(), &props);
+	pipelines_cache.buffer.resize(sizeof(PipelineCacheHeader));
+	PipelineCacheHeader *header = (PipelineCacheHeader *)pipelines_cache.buffer.ptrw();
+	*header = {};
+	header->magic = 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
+	header->device_id = props.deviceID;
+	header->vendor_id = props.vendorID;
+	header->driver_version = props.driverVersion;
+	memcpy(header->uuid, props.pipelineCacheUUID, VK_UUID_SIZE);
+	header->driver_abi = sizeof(void *);
+
+	limits = context->get_device_limits();
+}
+
+RenderingDeviceDriverVulkan::~RenderingDeviceDriverVulkan() {
+	while (small_allocs_pools.size()) {
+		HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin();
+		vmaDestroyPool(allocator, E->value);
+		small_allocs_pools.remove(E);
+	}
+	vmaDestroyAllocator(allocator);
+}

+ 482 - 0
drivers/vulkan/rendering_device_driver_vulkan.h

@@ -0,0 +1,482 @@
+/**************************************************************************/
+/*  rendering_device_driver_vulkan.h                                      */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_DEVICE_DRIVER_VULKAN_H
+#define RENDERING_DEVICE_DRIVER_VULKAN_H
+
+#include "core/templates/hash_map.h"
+#include "core/templates/paged_allocator.h"
+#include "servers/rendering/rendering_device_driver.h"
+
+#ifdef DEBUG_ENABLED
+#ifndef _MSC_VER
+#define _DEBUG
+#endif
+#endif
+#include "thirdparty/vulkan/vk_mem_alloc.h"
+
+#ifdef USE_VOLK
+#include <volk.h>
+#else
+#include <vulkan/vulkan.h>
+#endif
+
+class VulkanContext;
+
+// Design principles:
+// - Vulkan structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply).
+class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
+	/*****************/
+	/**** GENERIC ****/
+	/*****************/
+
+	VulkanContext *context = nullptr;
+	VkDevice vk_device = VK_NULL_HANDLE; // Owned by the context.
+
+	/****************/
+	/**** MEMORY ****/
+	/****************/
+
+	VmaAllocator allocator = nullptr;
+	HashMap<uint32_t, VmaPool> small_allocs_pools;
+
+	VmaPool _find_or_create_small_allocs_pool(uint32_t p_mem_type_index);
+
+	/*****************/
+	/**** BUFFERS ****/
+	/*****************/
+private:
+	struct BufferInfo {
+		VkBuffer vk_buffer = VK_NULL_HANDLE;
+		struct {
+			VmaAllocation handle = nullptr;
+			uint64_t size = UINT64_MAX;
+		} allocation;
+		uint64_t size = 0;
+		VkBufferView vk_view = VK_NULL_HANDLE; // For texel buffers.
+	};
+
+public:
+	virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) override final;
+	virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) override final;
+	virtual void buffer_free(BufferID p_buffer) override final;
+	virtual uint64_t buffer_get_allocation_size(BufferID p_buffer) override final;
+	virtual uint8_t *buffer_map(BufferID p_buffer) override final;
+	virtual void buffer_unmap(BufferID p_buffer) override final;
+
+	/*****************/
+	/**** TEXTURE ****/
+	/*****************/
+
+	struct TextureInfo {
+		VkImageView vk_view = VK_NULL_HANDLE;
+		DataFormat rd_format = DATA_FORMAT_MAX;
+		VkImageCreateInfo vk_create_info = {};
+		VkImageViewCreateInfo vk_view_create_info = {};
+		struct {
+			VmaAllocation handle = nullptr;
+			VmaAllocationInfo info = {};
+		} allocation; // All 0/null if just a view.
+	};
+
+	VkSampleCountFlagBits _ensure_supported_sample_count(TextureSamples p_requested_sample_count);
+
+public:
+	virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) override final;
+	virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
+	virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) override final;
+	virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) override final;
+	virtual void texture_free(TextureID p_texture) override final;
+	virtual uint64_t texture_get_allocation_size(TextureID p_texture) override final;
+	virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) override final;
+	virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final;
+	virtual void texture_unmap(TextureID p_texture) override final;
+	virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final;
+
+	/*****************/
+	/**** SAMPLER ****/
+	/*****************/
+public:
+	virtual SamplerID sampler_create(const SamplerState &p_state) final override;
+	virtual void sampler_free(SamplerID p_sampler) final override;
+	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) override final;
+
+	/**********************/
+	/**** VERTEX ARRAY ****/
+	/**********************/
+private:
+	struct VertexFormatInfo {
+		TightLocalVector<VkVertexInputBindingDescription> vk_bindings;
+		TightLocalVector<VkVertexInputAttributeDescription> vk_attributes;
+		VkPipelineVertexInputStateCreateInfo vk_create_info = {};
+	};
+
+public:
+	virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
+	virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
+
+	/******************/
+	/**** BARRIERS ****/
+	/******************/
+
+	virtual void command_pipeline_barrier(
+			CommandBufferID p_cmd_buffer,
+			BitField<PipelineStageBits> p_src_stages,
+			BitField<PipelineStageBits> p_dst_stages,
+			VectorView<MemoryBarrier> p_memory_barriers,
+			VectorView<BufferBarrier> p_buffer_barriers,
+			VectorView<TextureBarrier> p_texture_barriers) override final;
+
+	/*************************/
+	/**** COMMAND BUFFERS ****/
+	/*************************/
+private:
+#ifdef DEBUG_ENABLED
+	// Vulkan doesn't need to know if the command buffers created in a pool
+	// will be primary or secondary, but RDD works like that, so we will enforce.
+
+	HashSet<CommandPoolID> secondary_cmd_pools;
+	HashSet<CommandBufferID> secondary_cmd_buffers;
+#endif
+
+public:
+	// ----- POOL -----
+
+	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) override final;
+	virtual void command_pool_free(CommandPoolID p_cmd_pool) override final;
+
+	// ----- BUFFER -----
+
+	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) override final;
+	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) override final;
+	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) override final;
+	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) override final;
+	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) override final;
+
+	/*********************/
+	/**** FRAMEBUFFER ****/
+	/*********************/
+
+	virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) override final;
+	virtual void framebuffer_free(FramebufferID p_framebuffer) override final;
+
+	/****************/
+	/**** SHADER ****/
+	/****************/
+private:
+	struct ShaderBinary {
+		// Version 1: initial.
+		// Version 2: Added shader name.
+		// Version 3: Added writable.
+		// Version 4: 64-bit vertex input mask.
+		static const uint32_t VERSION = 4;
+
+		struct DataBinding {
+			uint32_t type = 0;
+			uint32_t binding = 0;
+			uint32_t stages = 0;
+			uint32_t length = 0; // Size of arrays (in total elements), or UBOs (in bytes * total elements).
+			uint32_t writable = 0;
+		};
+
+		struct SpecializationConstant {
+			uint32_t type = 0;
+			uint32_t constant_id = 0;
+			uint32_t int_value = 0;
+			uint32_t stage_flags = 0;
+		};
+
+		struct Data {
+			uint64_t vertex_input_mask = 0;
+			uint32_t fragment_output_mask = 0;
+			uint32_t specialization_constants_count = 0;
+			uint32_t is_compute = 0;
+			uint32_t compute_local_size[3] = {};
+			uint32_t set_count = 0;
+			uint32_t push_constant_size = 0;
+			uint32_t vk_push_constant_stages_mask = 0;
+			uint32_t stage_count = 0;
+			uint32_t shader_name_len = 0;
+		};
+	};
+
+	struct ShaderInfo {
+		VkShaderStageFlags vk_push_constant_stages = 0;
+		TightLocalVector<VkPipelineShaderStageCreateInfo> vk_stages_create_info;
+		TightLocalVector<VkDescriptorSetLayout> vk_descriptor_set_layouts;
+		VkPipelineLayout vk_pipeline_layout = VK_NULL_HANDLE;
+	};
+
+public:
+	virtual String shader_get_binary_cache_key() override final;
+	virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) override final;
+	virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
+	virtual void shader_free(ShaderID p_shader) override final;
+
+	/*********************/
+	/**** UNIFORM SET ****/
+	/*********************/
+
+	// Descriptor sets require allocation from a pool.
+	// The documentation on how to use pools properly
+	// is scarce, and the documentation is strange.
+	//
+	// Basically, you can mix and match pools as you
+	// like, but you'll run into fragmentation issues.
+	// Because of this, the recommended approach is to
+	// create a pool for every descriptor set type, as
+	// this prevents fragmentation.
+	//
+	// This is implemented here as a having a list of
+	// pools (each can contain up to 64 sets) for each
+	// set layout. The amount of sets for each type
+	// is used as the key.
+
+private:
+	static const uint32_t MAX_UNIFORM_POOL_ELEMENT = 65535;
+
+	struct DescriptorSetPoolKey {
+		uint16_t uniform_type[UNIFORM_TYPE_MAX] = {};
+
+		bool operator<(const DescriptorSetPoolKey &p_other) const {
+			return memcmp(uniform_type, p_other.uniform_type, sizeof(uniform_type)) < 0;
+		}
+	};
+
+	using DescriptorSetPools = RBMap<DescriptorSetPoolKey, HashMap<VkDescriptorPool, uint32_t>>;
+	DescriptorSetPools descriptor_set_pools;
+	uint32_t max_descriptor_sets_per_pool = 0;
+
+	VkDescriptorPool _descriptor_set_pool_find_or_create(const DescriptorSetPoolKey &p_key, DescriptorSetPools::Iterator *r_pool_sets_it);
+	void _descriptor_set_pool_unreference(DescriptorSetPools::Iterator p_pool_sets_it, VkDescriptorPool p_vk_descriptor_pool);
+
+	struct UniformSetInfo {
+		VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE;
+		VkDescriptorPool vk_descriptor_pool = VK_NULL_HANDLE;
+		DescriptorSetPools::Iterator pool_sets_it = {};
+	};
+
+public:
+	virtual UniformSetID uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) override final;
+	virtual void uniform_set_free(UniformSetID p_uniform_set) override final;
+
+	// ----- COMMANDS -----
+
+	virtual void command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+	/******************/
+	/**** TRANSFER ****/
+	/******************/
+
+	virtual void command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) override final;
+	virtual void command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) override final;
+
+	virtual void command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) override final;
+	virtual void command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) override final;
+	virtual void command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) override final;
+
+	virtual void command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) override final;
+	virtual void command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) override final;
+
+	/******************/
+	/**** PIPELINE ****/
+	/******************/
+private:
+	struct PipelineCacheHeader {
+		uint32_t magic = 0;
+		uint32_t data_size = 0;
+		uint64_t data_hash = 0;
+		uint32_t vendor_id = 0;
+		uint32_t device_id = 0;
+		uint32_t driver_version = 0;
+		uint8_t uuid[VK_UUID_SIZE] = {};
+		uint8_t driver_abi = 0;
+	};
+
+	struct PipelineCache {
+		String file_path;
+		size_t current_size = 0;
+		Vector<uint8_t> buffer; // Header then data.
+		VkPipelineCache vk_cache = VK_NULL_HANDLE;
+	};
+
+	static int caching_instance_count;
+	PipelineCache pipelines_cache;
+
+public:
+	virtual void pipeline_free(PipelineID p_pipeline) override final;
+
+	// ----- BINDING -----
+
+	virtual void command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_first_index, VectorView<uint32_t> p_data) override final;
+
+	// ----- CACHE -----
+
+	virtual bool pipeline_cache_create(const Vector<uint8_t> &p_data) override final;
+	virtual void pipeline_cache_free() override final;
+	virtual size_t pipeline_cache_query_size() override final;
+	virtual Vector<uint8_t> pipeline_cache_serialize() override final;
+
+	/*******************/
+	/**** RENDERING ****/
+	/*******************/
+
+	// ----- SUBPASS -----
+
+	virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
+	virtual void render_pass_free(RenderPassID p_render_pass) override final;
+
+	// ----- COMMANDS -----
+
+	virtual void command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) override final;
+	virtual void command_end_render_pass(CommandBufferID p_cmd_buffer) override final;
+	virtual void command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) override final;
+	virtual void command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) override final;
+	virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) override final;
+	virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) override final;
+
+	// Binding.
+	virtual void command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
+	virtual void command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+	// Drawing.
+	virtual void command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) override final;
+	virtual void command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) override final;
+	virtual void command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) override final;
+	virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
+
+	// Buffer binding.
+	virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
+	virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
+
+	// Dynamic state.
+	virtual void command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) override final;
+	virtual void command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) override final;
+
+	// ----- PIPELINE -----
+
+	virtual PipelineID render_pipeline_create(
+			ShaderID p_shader,
+			VertexFormatID p_vertex_format,
+			RenderPrimitive p_render_primitive,
+			PipelineRasterizationState p_rasterization_state,
+			PipelineMultisampleState p_multisample_state,
+			PipelineDepthStencilState p_depth_stencil_state,
+			PipelineColorBlendState p_blend_state,
+			VectorView<int32_t> p_color_attachments,
+			BitField<PipelineDynamicStateFlags> p_dynamic_state,
+			RenderPassID p_render_pass,
+			uint32_t p_render_subpass,
+			VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
+
+	/*****************/
+	/**** COMPUTE ****/
+	/*****************/
+
+	// ----- COMMANDS -----
+
+	// Binding.
+	virtual void command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) override final;
+	virtual void command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
+
+	// Dispatching.
+	virtual void command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) override final;
+	virtual void command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) override final;
+
+	// ----- PIPELINE -----
+
+	virtual PipelineID compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) override final;
+
+	/*****************/
+	/**** QUERIES ****/
+	/*****************/
+
+	// ----- TIMESTAMP -----
+
+	// Basic.
+	virtual QueryPoolID timestamp_query_pool_create(uint32_t p_query_count) override final;
+	virtual void timestamp_query_pool_free(QueryPoolID p_pool_id) override final;
+	virtual void timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) override final;
+	virtual uint64_t timestamp_query_result_to_time(uint64_t p_result) override final;
+
+	// Commands.
+	virtual void command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) override final;
+	virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) override final;
+
+	/****************/
+	/**** SCREEN ****/
+	/****************/
+
+	virtual DataFormat screen_get_format() override final;
+
+	/********************/
+	/**** SUBMISSION ****/
+	/********************/
+
+	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
+	virtual void end_segment() override final;
+
+	/**************/
+	/**** MISC ****/
+	/**************/
+
+	VkPhysicalDeviceLimits limits = {};
+
+	virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) override final;
+	virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) override final;
+	virtual uint64_t get_total_memory_used() override final;
+	virtual uint64_t limit_get(Limit p_limit) override final;
+	virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
+	virtual bool has_feature(Features p_feature) override final;
+	virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
+
+private:
+	/*********************/
+	/**** BOOKKEEPING ****/
+	/*********************/
+
+	using VersatileResource = VersatileResourceTemplate<
+			BufferInfo,
+			TextureInfo,
+			VertexFormatInfo,
+			ShaderInfo,
+			UniformSetInfo>;
+	PagedAllocator<VersatileResource> resources_allocator;
+
+	/******************/
+
+public:
+	RenderingDeviceDriverVulkan(VulkanContext *p_context, VkDevice p_vk_device);
+	virtual ~RenderingDeviceDriverVulkan();
+};
+
+#endif // RENDERING_DEVICE_DRIVER_VULKAN_H

+ 0 - 9765
drivers/vulkan/rendering_device_vulkan.cpp

@@ -1,9765 +0,0 @@
-/**************************************************************************/
-/*  rendering_device_vulkan.cpp                                           */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "rendering_device_vulkan.h"
-
-#include "core/config/project_settings.h"
-#include "core/io/compression.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/marshalls.h"
-#include "core/os/os.h"
-#include "core/templates/hashfuncs.h"
-#include "drivers/vulkan/vulkan_context.h"
-
-#include "thirdparty/misc/smolv.h"
-
-//#define FORCE_FULL_BARRIER
-
-static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
-
-// Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values).
-RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, BitField<BarrierMask> p_post_barrier) {
-	Buffer *buffer = nullptr;
-	if (vertex_buffer_owner.owns(p_buffer)) {
-		buffer = vertex_buffer_owner.get_or_null(p_buffer);
-
-		r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
-		r_access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
-		if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
-			if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-				r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-				r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			}
-			if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-				r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-				r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			}
-			if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-				r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-				r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			}
-		}
-	} else if (index_buffer_owner.owns(p_buffer)) {
-		r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
-		r_access_mask |= VK_ACCESS_INDEX_READ_BIT;
-		buffer = index_buffer_owner.get_or_null(p_buffer);
-	} else if (uniform_buffer_owner.owns(p_buffer)) {
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		}
-		r_access_mask |= VK_ACCESS_UNIFORM_READ_BIT;
-		buffer = uniform_buffer_owner.get_or_null(p_buffer);
-	} else if (texture_buffer_owner.owns(p_buffer)) {
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
-		}
-
-		buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer;
-	} else if (storage_buffer_owner.owns(p_buffer)) {
-		buffer = storage_buffer_owner.get_or_null(p_buffer);
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-
-		if (buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) {
-			r_stage_mask |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
-			r_access_mask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
-		}
-	}
-	return buffer;
-}
-
-static void update_external_dependency_for_store(VkSubpassDependency2KHR &dependency, bool is_sampled, bool is_storage, bool is_depth) {
-	// Transitioning from write to read, protect the shaders that may use this next.
-	// Allow for copies/image layout transitions.
-	dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-	dependency.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
-
-	if (is_sampled) {
-		dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
-	} else if (is_storage) {
-		dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-	} else {
-		dependency.dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-		dependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-	}
-
-	if (is_depth) {
-		// Depth resources have additional stages that may be interested in them.
-		dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-		dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-	}
-}
-
-void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
-	if (!dependency_map.has(p_depends_on)) {
-		dependency_map[p_depends_on] = HashSet<RID>();
-	}
-
-	dependency_map[p_depends_on].insert(p_id);
-
-	if (!reverse_dependency_map.has(p_id)) {
-		reverse_dependency_map[p_id] = HashSet<RID>();
-	}
-
-	reverse_dependency_map[p_id].insert(p_depends_on);
-}
-
-void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
-	// Direct dependencies must be freed.
-
-	HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);
-	if (E) {
-		while (E->value.size()) {
-			free(*E->value.begin());
-		}
-		dependency_map.remove(E);
-	}
-
-	// Reverse dependencies must be unreferenced.
-	E = reverse_dependency_map.find(p_id);
-
-	if (E) {
-		for (const RID &F : E->value) {
-			HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F);
-			ERR_CONTINUE(!G);
-			ERR_CONTINUE(!G->value.has(p_id));
-			G->value.erase(p_id);
-		}
-
-		reverse_dependency_map.remove(E);
-	}
-}
-
-const VkFormat RenderingDeviceVulkan::vulkan_formats[RenderingDevice::DATA_FORMAT_MAX] = {
-	VK_FORMAT_R4G4_UNORM_PACK8,
-	VK_FORMAT_R4G4B4A4_UNORM_PACK16,
-	VK_FORMAT_B4G4R4A4_UNORM_PACK16,
-	VK_FORMAT_R5G6B5_UNORM_PACK16,
-	VK_FORMAT_B5G6R5_UNORM_PACK16,
-	VK_FORMAT_R5G5B5A1_UNORM_PACK16,
-	VK_FORMAT_B5G5R5A1_UNORM_PACK16,
-	VK_FORMAT_A1R5G5B5_UNORM_PACK16,
-	VK_FORMAT_R8_UNORM,
-	VK_FORMAT_R8_SNORM,
-	VK_FORMAT_R8_USCALED,
-	VK_FORMAT_R8_SSCALED,
-	VK_FORMAT_R8_UINT,
-	VK_FORMAT_R8_SINT,
-	VK_FORMAT_R8_SRGB,
-	VK_FORMAT_R8G8_UNORM,
-	VK_FORMAT_R8G8_SNORM,
-	VK_FORMAT_R8G8_USCALED,
-	VK_FORMAT_R8G8_SSCALED,
-	VK_FORMAT_R8G8_UINT,
-	VK_FORMAT_R8G8_SINT,
-	VK_FORMAT_R8G8_SRGB,
-	VK_FORMAT_R8G8B8_UNORM,
-	VK_FORMAT_R8G8B8_SNORM,
-	VK_FORMAT_R8G8B8_USCALED,
-	VK_FORMAT_R8G8B8_SSCALED,
-	VK_FORMAT_R8G8B8_UINT,
-	VK_FORMAT_R8G8B8_SINT,
-	VK_FORMAT_R8G8B8_SRGB,
-	VK_FORMAT_B8G8R8_UNORM,
-	VK_FORMAT_B8G8R8_SNORM,
-	VK_FORMAT_B8G8R8_USCALED,
-	VK_FORMAT_B8G8R8_SSCALED,
-	VK_FORMAT_B8G8R8_UINT,
-	VK_FORMAT_B8G8R8_SINT,
-	VK_FORMAT_B8G8R8_SRGB,
-	VK_FORMAT_R8G8B8A8_UNORM,
-	VK_FORMAT_R8G8B8A8_SNORM,
-	VK_FORMAT_R8G8B8A8_USCALED,
-	VK_FORMAT_R8G8B8A8_SSCALED,
-	VK_FORMAT_R8G8B8A8_UINT,
-	VK_FORMAT_R8G8B8A8_SINT,
-	VK_FORMAT_R8G8B8A8_SRGB,
-	VK_FORMAT_B8G8R8A8_UNORM,
-	VK_FORMAT_B8G8R8A8_SNORM,
-	VK_FORMAT_B8G8R8A8_USCALED,
-	VK_FORMAT_B8G8R8A8_SSCALED,
-	VK_FORMAT_B8G8R8A8_UINT,
-	VK_FORMAT_B8G8R8A8_SINT,
-	VK_FORMAT_B8G8R8A8_SRGB,
-	VK_FORMAT_A8B8G8R8_UNORM_PACK32,
-	VK_FORMAT_A8B8G8R8_SNORM_PACK32,
-	VK_FORMAT_A8B8G8R8_USCALED_PACK32,
-	VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
-	VK_FORMAT_A8B8G8R8_UINT_PACK32,
-	VK_FORMAT_A8B8G8R8_SINT_PACK32,
-	VK_FORMAT_A8B8G8R8_SRGB_PACK32,
-	VK_FORMAT_A2R10G10B10_UNORM_PACK32,
-	VK_FORMAT_A2R10G10B10_SNORM_PACK32,
-	VK_FORMAT_A2R10G10B10_USCALED_PACK32,
-	VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
-	VK_FORMAT_A2R10G10B10_UINT_PACK32,
-	VK_FORMAT_A2R10G10B10_SINT_PACK32,
-	VK_FORMAT_A2B10G10R10_UNORM_PACK32,
-	VK_FORMAT_A2B10G10R10_SNORM_PACK32,
-	VK_FORMAT_A2B10G10R10_USCALED_PACK32,
-	VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
-	VK_FORMAT_A2B10G10R10_UINT_PACK32,
-	VK_FORMAT_A2B10G10R10_SINT_PACK32,
-	VK_FORMAT_R16_UNORM,
-	VK_FORMAT_R16_SNORM,
-	VK_FORMAT_R16_USCALED,
-	VK_FORMAT_R16_SSCALED,
-	VK_FORMAT_R16_UINT,
-	VK_FORMAT_R16_SINT,
-	VK_FORMAT_R16_SFLOAT,
-	VK_FORMAT_R16G16_UNORM,
-	VK_FORMAT_R16G16_SNORM,
-	VK_FORMAT_R16G16_USCALED,
-	VK_FORMAT_R16G16_SSCALED,
-	VK_FORMAT_R16G16_UINT,
-	VK_FORMAT_R16G16_SINT,
-	VK_FORMAT_R16G16_SFLOAT,
-	VK_FORMAT_R16G16B16_UNORM,
-	VK_FORMAT_R16G16B16_SNORM,
-	VK_FORMAT_R16G16B16_USCALED,
-	VK_FORMAT_R16G16B16_SSCALED,
-	VK_FORMAT_R16G16B16_UINT,
-	VK_FORMAT_R16G16B16_SINT,
-	VK_FORMAT_R16G16B16_SFLOAT,
-	VK_FORMAT_R16G16B16A16_UNORM,
-	VK_FORMAT_R16G16B16A16_SNORM,
-	VK_FORMAT_R16G16B16A16_USCALED,
-	VK_FORMAT_R16G16B16A16_SSCALED,
-	VK_FORMAT_R16G16B16A16_UINT,
-	VK_FORMAT_R16G16B16A16_SINT,
-	VK_FORMAT_R16G16B16A16_SFLOAT,
-	VK_FORMAT_R32_UINT,
-	VK_FORMAT_R32_SINT,
-	VK_FORMAT_R32_SFLOAT,
-	VK_FORMAT_R32G32_UINT,
-	VK_FORMAT_R32G32_SINT,
-	VK_FORMAT_R32G32_SFLOAT,
-	VK_FORMAT_R32G32B32_UINT,
-	VK_FORMAT_R32G32B32_SINT,
-	VK_FORMAT_R32G32B32_SFLOAT,
-	VK_FORMAT_R32G32B32A32_UINT,
-	VK_FORMAT_R32G32B32A32_SINT,
-	VK_FORMAT_R32G32B32A32_SFLOAT,
-	VK_FORMAT_R64_UINT,
-	VK_FORMAT_R64_SINT,
-	VK_FORMAT_R64_SFLOAT,
-	VK_FORMAT_R64G64_UINT,
-	VK_FORMAT_R64G64_SINT,
-	VK_FORMAT_R64G64_SFLOAT,
-	VK_FORMAT_R64G64B64_UINT,
-	VK_FORMAT_R64G64B64_SINT,
-	VK_FORMAT_R64G64B64_SFLOAT,
-	VK_FORMAT_R64G64B64A64_UINT,
-	VK_FORMAT_R64G64B64A64_SINT,
-	VK_FORMAT_R64G64B64A64_SFLOAT,
-	VK_FORMAT_B10G11R11_UFLOAT_PACK32,
-	VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
-	VK_FORMAT_D16_UNORM,
-	VK_FORMAT_X8_D24_UNORM_PACK32,
-	VK_FORMAT_D32_SFLOAT,
-	VK_FORMAT_S8_UINT,
-	VK_FORMAT_D16_UNORM_S8_UINT,
-	VK_FORMAT_D24_UNORM_S8_UINT,
-	VK_FORMAT_D32_SFLOAT_S8_UINT,
-	VK_FORMAT_BC1_RGB_UNORM_BLOCK,
-	VK_FORMAT_BC1_RGB_SRGB_BLOCK,
-	VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
-	VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
-	VK_FORMAT_BC2_UNORM_BLOCK,
-	VK_FORMAT_BC2_SRGB_BLOCK,
-	VK_FORMAT_BC3_UNORM_BLOCK,
-	VK_FORMAT_BC3_SRGB_BLOCK,
-	VK_FORMAT_BC4_UNORM_BLOCK,
-	VK_FORMAT_BC4_SNORM_BLOCK,
-	VK_FORMAT_BC5_UNORM_BLOCK,
-	VK_FORMAT_BC5_SNORM_BLOCK,
-	VK_FORMAT_BC6H_UFLOAT_BLOCK,
-	VK_FORMAT_BC6H_SFLOAT_BLOCK,
-	VK_FORMAT_BC7_UNORM_BLOCK,
-	VK_FORMAT_BC7_SRGB_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
-	VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
-	VK_FORMAT_EAC_R11_UNORM_BLOCK,
-	VK_FORMAT_EAC_R11_SNORM_BLOCK,
-	VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
-	VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
-	VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
-	VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
-	VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
-	VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
-	VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
-	VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
-	VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
-	VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
-	VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
-	VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
-	VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
-	VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
-	VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
-	VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
-	VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
-	VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
-	VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
-	VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
-	VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
-	VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
-	VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
-	VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
-	VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
-	VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
-	VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
-	VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
-	VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
-	VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
-	VK_FORMAT_G8B8G8R8_422_UNORM,
-	VK_FORMAT_B8G8R8G8_422_UNORM,
-	VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
-	VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
-	VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
-	VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
-	VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
-	VK_FORMAT_R10X6_UNORM_PACK16,
-	VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
-	VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
-	VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
-	VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
-	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
-	VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
-	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
-	VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
-	VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
-	VK_FORMAT_R12X4_UNORM_PACK16,
-	VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
-	VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
-	VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
-	VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
-	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
-	VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
-	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
-	VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
-	VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
-	VK_FORMAT_G16B16G16R16_422_UNORM,
-	VK_FORMAT_B16G16R16G16_422_UNORM,
-	VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
-	VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
-	VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
-	VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
-	VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
-};
-
-const char *RenderingDeviceVulkan::named_formats[RenderingDevice::DATA_FORMAT_MAX] = {
-	"R4G4_Unorm_Pack8",
-	"R4G4B4A4_Unorm_Pack16",
-	"B4G4R4A4_Unorm_Pack16",
-	"R5G6B5_Unorm_Pack16",
-	"B5G6R5_Unorm_Pack16",
-	"R5G5B5A1_Unorm_Pack16",
-	"B5G5R5A1_Unorm_Pack16",
-	"A1R5G5B5_Unorm_Pack16",
-	"R8_Unorm",
-	"R8_Snorm",
-	"R8_Uscaled",
-	"R8_Sscaled",
-	"R8_Uint",
-	"R8_Sint",
-	"R8_Srgb",
-	"R8G8_Unorm",
-	"R8G8_Snorm",
-	"R8G8_Uscaled",
-	"R8G8_Sscaled",
-	"R8G8_Uint",
-	"R8G8_Sint",
-	"R8G8_Srgb",
-	"R8G8B8_Unorm",
-	"R8G8B8_Snorm",
-	"R8G8B8_Uscaled",
-	"R8G8B8_Sscaled",
-	"R8G8B8_Uint",
-	"R8G8B8_Sint",
-	"R8G8B8_Srgb",
-	"B8G8R8_Unorm",
-	"B8G8R8_Snorm",
-	"B8G8R8_Uscaled",
-	"B8G8R8_Sscaled",
-	"B8G8R8_Uint",
-	"B8G8R8_Sint",
-	"B8G8R8_Srgb",
-	"R8G8B8A8_Unorm",
-	"R8G8B8A8_Snorm",
-	"R8G8B8A8_Uscaled",
-	"R8G8B8A8_Sscaled",
-	"R8G8B8A8_Uint",
-	"R8G8B8A8_Sint",
-	"R8G8B8A8_Srgb",
-	"B8G8R8A8_Unorm",
-	"B8G8R8A8_Snorm",
-	"B8G8R8A8_Uscaled",
-	"B8G8R8A8_Sscaled",
-	"B8G8R8A8_Uint",
-	"B8G8R8A8_Sint",
-	"B8G8R8A8_Srgb",
-	"A8B8G8R8_Unorm_Pack32",
-	"A8B8G8R8_Snorm_Pack32",
-	"A8B8G8R8_Uscaled_Pack32",
-	"A8B8G8R8_Sscaled_Pack32",
-	"A8B8G8R8_Uint_Pack32",
-	"A8B8G8R8_Sint_Pack32",
-	"A8B8G8R8_Srgb_Pack32",
-	"A2R10G10B10_Unorm_Pack32",
-	"A2R10G10B10_Snorm_Pack32",
-	"A2R10G10B10_Uscaled_Pack32",
-	"A2R10G10B10_Sscaled_Pack32",
-	"A2R10G10B10_Uint_Pack32",
-	"A2R10G10B10_Sint_Pack32",
-	"A2B10G10R10_Unorm_Pack32",
-	"A2B10G10R10_Snorm_Pack32",
-	"A2B10G10R10_Uscaled_Pack32",
-	"A2B10G10R10_Sscaled_Pack32",
-	"A2B10G10R10_Uint_Pack32",
-	"A2B10G10R10_Sint_Pack32",
-	"R16_Unorm",
-	"R16_Snorm",
-	"R16_Uscaled",
-	"R16_Sscaled",
-	"R16_Uint",
-	"R16_Sint",
-	"R16_Sfloat",
-	"R16G16_Unorm",
-	"R16G16_Snorm",
-	"R16G16_Uscaled",
-	"R16G16_Sscaled",
-	"R16G16_Uint",
-	"R16G16_Sint",
-	"R16G16_Sfloat",
-	"R16G16B16_Unorm",
-	"R16G16B16_Snorm",
-	"R16G16B16_Uscaled",
-	"R16G16B16_Sscaled",
-	"R16G16B16_Uint",
-	"R16G16B16_Sint",
-	"R16G16B16_Sfloat",
-	"R16G16B16A16_Unorm",
-	"R16G16B16A16_Snorm",
-	"R16G16B16A16_Uscaled",
-	"R16G16B16A16_Sscaled",
-	"R16G16B16A16_Uint",
-	"R16G16B16A16_Sint",
-	"R16G16B16A16_Sfloat",
-	"R32_Uint",
-	"R32_Sint",
-	"R32_Sfloat",
-	"R32G32_Uint",
-	"R32G32_Sint",
-	"R32G32_Sfloat",
-	"R32G32B32_Uint",
-	"R32G32B32_Sint",
-	"R32G32B32_Sfloat",
-	"R32G32B32A32_Uint",
-	"R32G32B32A32_Sint",
-	"R32G32B32A32_Sfloat",
-	"R64_Uint",
-	"R64_Sint",
-	"R64_Sfloat",
-	"R64G64_Uint",
-	"R64G64_Sint",
-	"R64G64_Sfloat",
-	"R64G64B64_Uint",
-	"R64G64B64_Sint",
-	"R64G64B64_Sfloat",
-	"R64G64B64A64_Uint",
-	"R64G64B64A64_Sint",
-	"R64G64B64A64_Sfloat",
-	"B10G11R11_Ufloat_Pack32",
-	"E5B9G9R9_Ufloat_Pack32",
-	"D16_Unorm",
-	"X8_D24_Unorm_Pack32",
-	"D32_Sfloat",
-	"S8_Uint",
-	"D16_Unorm_S8_Uint",
-	"D24_Unorm_S8_Uint",
-	"D32_Sfloat_S8_Uint",
-	"Bc1_Rgb_Unorm_Block",
-	"Bc1_Rgb_Srgb_Block",
-	"Bc1_Rgba_Unorm_Block",
-	"Bc1_Rgba_Srgb_Block",
-	"Bc2_Unorm_Block",
-	"Bc2_Srgb_Block",
-	"Bc3_Unorm_Block",
-	"Bc3_Srgb_Block",
-	"Bc4_Unorm_Block",
-	"Bc4_Snorm_Block",
-	"Bc5_Unorm_Block",
-	"Bc5_Snorm_Block",
-	"Bc6H_Ufloat_Block",
-	"Bc6H_Sfloat_Block",
-	"Bc7_Unorm_Block",
-	"Bc7_Srgb_Block",
-	"Etc2_R8G8B8_Unorm_Block",
-	"Etc2_R8G8B8_Srgb_Block",
-	"Etc2_R8G8B8A1_Unorm_Block",
-	"Etc2_R8G8B8A1_Srgb_Block",
-	"Etc2_R8G8B8A8_Unorm_Block",
-	"Etc2_R8G8B8A8_Srgb_Block",
-	"Eac_R11_Unorm_Block",
-	"Eac_R11_Snorm_Block",
-	"Eac_R11G11_Unorm_Block",
-	"Eac_R11G11_Snorm_Block",
-	"Astc_4X4_Unorm_Block",
-	"Astc_4X4_Srgb_Block",
-	"Astc_5X4_Unorm_Block",
-	"Astc_5X4_Srgb_Block",
-	"Astc_5X5_Unorm_Block",
-	"Astc_5X5_Srgb_Block",
-	"Astc_6X5_Unorm_Block",
-	"Astc_6X5_Srgb_Block",
-	"Astc_6X6_Unorm_Block",
-	"Astc_6X6_Srgb_Block",
-	"Astc_8X5_Unorm_Block",
-	"Astc_8X5_Srgb_Block",
-	"Astc_8X6_Unorm_Block",
-	"Astc_8X6_Srgb_Block",
-	"Astc_8X8_Unorm_Block",
-	"Astc_8X8_Srgb_Block",
-	"Astc_10X5_Unorm_Block",
-	"Astc_10X5_Srgb_Block",
-	"Astc_10X6_Unorm_Block",
-	"Astc_10X6_Srgb_Block",
-	"Astc_10X8_Unorm_Block",
-	"Astc_10X8_Srgb_Block",
-	"Astc_10X10_Unorm_Block",
-	"Astc_10X10_Srgb_Block",
-	"Astc_12X10_Unorm_Block",
-	"Astc_12X10_Srgb_Block",
-	"Astc_12X12_Unorm_Block",
-	"Astc_12X12_Srgb_Block",
-	"G8B8G8R8_422_Unorm",
-	"B8G8R8G8_422_Unorm",
-	"G8_B8_R8_3Plane_420_Unorm",
-	"G8_B8R8_2Plane_420_Unorm",
-	"G8_B8_R8_3Plane_422_Unorm",
-	"G8_B8R8_2Plane_422_Unorm",
-	"G8_B8_R8_3Plane_444_Unorm",
-	"R10X6_Unorm_Pack16",
-	"R10X6G10X6_Unorm_2Pack16",
-	"R10X6G10X6B10X6A10X6_Unorm_4Pack16",
-	"G10X6B10X6G10X6R10X6_422_Unorm_4Pack16",
-	"B10X6G10X6R10X6G10X6_422_Unorm_4Pack16",
-	"G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16",
-	"G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16",
-	"G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16",
-	"G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16",
-	"G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16",
-	"R12X4_Unorm_Pack16",
-	"R12X4G12X4_Unorm_2Pack16",
-	"R12X4G12X4B12X4A12X4_Unorm_4Pack16",
-	"G12X4B12X4G12X4R12X4_422_Unorm_4Pack16",
-	"B12X4G12X4R12X4G12X4_422_Unorm_4Pack16",
-	"G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16",
-	"G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16",
-	"G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16",
-	"G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16",
-	"G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16",
-	"G16B16G16R16_422_Unorm",
-	"B16G16R16G16_422_Unorm",
-	"G16_B16_R16_3Plane_420_Unorm",
-	"G16_B16R16_2Plane_420_Unorm",
-	"G16_B16_R16_3Plane_422_Unorm",
-	"G16_B16R16_2Plane_422_Unorm",
-	"G16_B16_R16_3Plane_444_Unorm",
-};
-
-int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_R8_UNORM:
-		case DATA_FORMAT_R8_SNORM:
-		case DATA_FORMAT_R8_UINT:
-		case DATA_FORMAT_R8_SINT:
-		case DATA_FORMAT_R8G8_UNORM:
-		case DATA_FORMAT_R8G8_SNORM:
-		case DATA_FORMAT_R8G8_UINT:
-		case DATA_FORMAT_R8G8_SINT:
-		case DATA_FORMAT_R8G8B8_UNORM:
-		case DATA_FORMAT_R8G8B8_SNORM:
-		case DATA_FORMAT_R8G8B8_UINT:
-		case DATA_FORMAT_R8G8B8_SINT:
-		case DATA_FORMAT_B8G8R8_UNORM:
-		case DATA_FORMAT_B8G8R8_SNORM:
-		case DATA_FORMAT_B8G8R8_UINT:
-		case DATA_FORMAT_B8G8R8_SINT:
-		case DATA_FORMAT_R8G8B8A8_UNORM:
-		case DATA_FORMAT_R8G8B8A8_SNORM:
-		case DATA_FORMAT_R8G8B8A8_UINT:
-		case DATA_FORMAT_R8G8B8A8_SINT:
-		case DATA_FORMAT_B8G8R8A8_UNORM:
-		case DATA_FORMAT_B8G8R8A8_SNORM:
-		case DATA_FORMAT_B8G8R8A8_UINT:
-		case DATA_FORMAT_B8G8R8A8_SINT:
-		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
-			return 4;
-		case DATA_FORMAT_R16_UNORM:
-		case DATA_FORMAT_R16_SNORM:
-		case DATA_FORMAT_R16_UINT:
-		case DATA_FORMAT_R16_SINT:
-		case DATA_FORMAT_R16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16_UNORM:
-		case DATA_FORMAT_R16G16_SNORM:
-		case DATA_FORMAT_R16G16_UINT:
-		case DATA_FORMAT_R16G16_SINT:
-		case DATA_FORMAT_R16G16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16B16_UNORM:
-		case DATA_FORMAT_R16G16B16_SNORM:
-		case DATA_FORMAT_R16G16B16_UINT:
-		case DATA_FORMAT_R16G16B16_SINT:
-		case DATA_FORMAT_R16G16B16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R16G16B16A16_UNORM:
-		case DATA_FORMAT_R16G16B16A16_SNORM:
-		case DATA_FORMAT_R16G16B16A16_UINT:
-		case DATA_FORMAT_R16G16B16A16_SINT:
-		case DATA_FORMAT_R16G16B16A16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32_UINT:
-		case DATA_FORMAT_R32_SINT:
-		case DATA_FORMAT_R32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R32G32_UINT:
-		case DATA_FORMAT_R32G32_SINT:
-		case DATA_FORMAT_R32G32_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32G32B32_UINT:
-		case DATA_FORMAT_R32G32B32_SINT:
-		case DATA_FORMAT_R32G32B32_SFLOAT:
-			return 12;
-		case DATA_FORMAT_R32G32B32A32_UINT:
-		case DATA_FORMAT_R32G32B32A32_SINT:
-		case DATA_FORMAT_R32G32B32A32_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64_UINT:
-		case DATA_FORMAT_R64_SINT:
-		case DATA_FORMAT_R64_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R64G64_UINT:
-		case DATA_FORMAT_R64G64_SINT:
-		case DATA_FORMAT_R64G64_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64G64B64_UINT:
-		case DATA_FORMAT_R64G64B64_SINT:
-		case DATA_FORMAT_R64G64B64_SFLOAT:
-			return 24;
-		case DATA_FORMAT_R64G64B64A64_UINT:
-		case DATA_FORMAT_R64G64B64A64_SINT:
-		case DATA_FORMAT_R64G64B64A64_SFLOAT:
-			return 32;
-		default:
-			return 0;
-	}
-}
-
-uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_R4G4_UNORM_PACK8:
-			return 1;
-		case DATA_FORMAT_R4G4B4A4_UNORM_PACK16:
-		case DATA_FORMAT_B4G4R4A4_UNORM_PACK16:
-		case DATA_FORMAT_R5G6B5_UNORM_PACK16:
-		case DATA_FORMAT_B5G6R5_UNORM_PACK16:
-		case DATA_FORMAT_R5G5B5A1_UNORM_PACK16:
-		case DATA_FORMAT_B5G5R5A1_UNORM_PACK16:
-		case DATA_FORMAT_A1R5G5B5_UNORM_PACK16:
-			return 2;
-		case DATA_FORMAT_R8_UNORM:
-		case DATA_FORMAT_R8_SNORM:
-		case DATA_FORMAT_R8_USCALED:
-		case DATA_FORMAT_R8_SSCALED:
-		case DATA_FORMAT_R8_UINT:
-		case DATA_FORMAT_R8_SINT:
-		case DATA_FORMAT_R8_SRGB:
-			return 1;
-		case DATA_FORMAT_R8G8_UNORM:
-		case DATA_FORMAT_R8G8_SNORM:
-		case DATA_FORMAT_R8G8_USCALED:
-		case DATA_FORMAT_R8G8_SSCALED:
-		case DATA_FORMAT_R8G8_UINT:
-		case DATA_FORMAT_R8G8_SINT:
-		case DATA_FORMAT_R8G8_SRGB:
-			return 2;
-		case DATA_FORMAT_R8G8B8_UNORM:
-		case DATA_FORMAT_R8G8B8_SNORM:
-		case DATA_FORMAT_R8G8B8_USCALED:
-		case DATA_FORMAT_R8G8B8_SSCALED:
-		case DATA_FORMAT_R8G8B8_UINT:
-		case DATA_FORMAT_R8G8B8_SINT:
-		case DATA_FORMAT_R8G8B8_SRGB:
-		case DATA_FORMAT_B8G8R8_UNORM:
-		case DATA_FORMAT_B8G8R8_SNORM:
-		case DATA_FORMAT_B8G8R8_USCALED:
-		case DATA_FORMAT_B8G8R8_SSCALED:
-		case DATA_FORMAT_B8G8R8_UINT:
-		case DATA_FORMAT_B8G8R8_SINT:
-		case DATA_FORMAT_B8G8R8_SRGB:
-			return 3;
-		case DATA_FORMAT_R8G8B8A8_UNORM:
-		case DATA_FORMAT_R8G8B8A8_SNORM:
-		case DATA_FORMAT_R8G8B8A8_USCALED:
-		case DATA_FORMAT_R8G8B8A8_SSCALED:
-		case DATA_FORMAT_R8G8B8A8_UINT:
-		case DATA_FORMAT_R8G8B8A8_SINT:
-		case DATA_FORMAT_R8G8B8A8_SRGB:
-		case DATA_FORMAT_B8G8R8A8_UNORM:
-		case DATA_FORMAT_B8G8R8A8_SNORM:
-		case DATA_FORMAT_B8G8R8A8_USCALED:
-		case DATA_FORMAT_B8G8R8A8_SSCALED:
-		case DATA_FORMAT_B8G8R8A8_UINT:
-		case DATA_FORMAT_B8G8R8A8_SINT:
-		case DATA_FORMAT_B8G8R8A8_SRGB:
-			return 4;
-		case DATA_FORMAT_A8B8G8R8_UNORM_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SNORM_PACK32:
-		case DATA_FORMAT_A8B8G8R8_USCALED_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32:
-		case DATA_FORMAT_A8B8G8R8_UINT_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SINT_PACK32:
-		case DATA_FORMAT_A8B8G8R8_SRGB_PACK32:
-		case DATA_FORMAT_A2R10G10B10_UNORM_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SNORM_PACK32:
-		case DATA_FORMAT_A2R10G10B10_USCALED_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32:
-		case DATA_FORMAT_A2R10G10B10_UINT_PACK32:
-		case DATA_FORMAT_A2R10G10B10_SINT_PACK32:
-		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SNORM_PACK32:
-		case DATA_FORMAT_A2B10G10R10_USCALED_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32:
-		case DATA_FORMAT_A2B10G10R10_UINT_PACK32:
-		case DATA_FORMAT_A2B10G10R10_SINT_PACK32:
-			return 4;
-		case DATA_FORMAT_R16_UNORM:
-		case DATA_FORMAT_R16_SNORM:
-		case DATA_FORMAT_R16_USCALED:
-		case DATA_FORMAT_R16_SSCALED:
-		case DATA_FORMAT_R16_UINT:
-		case DATA_FORMAT_R16_SINT:
-		case DATA_FORMAT_R16_SFLOAT:
-			return 2;
-		case DATA_FORMAT_R16G16_UNORM:
-		case DATA_FORMAT_R16G16_SNORM:
-		case DATA_FORMAT_R16G16_USCALED:
-		case DATA_FORMAT_R16G16_SSCALED:
-		case DATA_FORMAT_R16G16_UINT:
-		case DATA_FORMAT_R16G16_SINT:
-		case DATA_FORMAT_R16G16_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R16G16B16_UNORM:
-		case DATA_FORMAT_R16G16B16_SNORM:
-		case DATA_FORMAT_R16G16B16_USCALED:
-		case DATA_FORMAT_R16G16B16_SSCALED:
-		case DATA_FORMAT_R16G16B16_UINT:
-		case DATA_FORMAT_R16G16B16_SINT:
-		case DATA_FORMAT_R16G16B16_SFLOAT:
-			return 6;
-		case DATA_FORMAT_R16G16B16A16_UNORM:
-		case DATA_FORMAT_R16G16B16A16_SNORM:
-		case DATA_FORMAT_R16G16B16A16_USCALED:
-		case DATA_FORMAT_R16G16B16A16_SSCALED:
-		case DATA_FORMAT_R16G16B16A16_UINT:
-		case DATA_FORMAT_R16G16B16A16_SINT:
-		case DATA_FORMAT_R16G16B16A16_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32_UINT:
-		case DATA_FORMAT_R32_SINT:
-		case DATA_FORMAT_R32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_R32G32_UINT:
-		case DATA_FORMAT_R32G32_SINT:
-		case DATA_FORMAT_R32G32_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R32G32B32_UINT:
-		case DATA_FORMAT_R32G32B32_SINT:
-		case DATA_FORMAT_R32G32B32_SFLOAT:
-			return 12;
-		case DATA_FORMAT_R32G32B32A32_UINT:
-		case DATA_FORMAT_R32G32B32A32_SINT:
-		case DATA_FORMAT_R32G32B32A32_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64_UINT:
-		case DATA_FORMAT_R64_SINT:
-		case DATA_FORMAT_R64_SFLOAT:
-			return 8;
-		case DATA_FORMAT_R64G64_UINT:
-		case DATA_FORMAT_R64G64_SINT:
-		case DATA_FORMAT_R64G64_SFLOAT:
-			return 16;
-		case DATA_FORMAT_R64G64B64_UINT:
-		case DATA_FORMAT_R64G64B64_SINT:
-		case DATA_FORMAT_R64G64B64_SFLOAT:
-			return 24;
-		case DATA_FORMAT_R64G64B64A64_UINT:
-		case DATA_FORMAT_R64G64B64A64_SINT:
-		case DATA_FORMAT_R64G64B64A64_SFLOAT:
-			return 32;
-		case DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
-		case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32:
-			return 4;
-		case DATA_FORMAT_D16_UNORM:
-			return 2;
-		case DATA_FORMAT_X8_D24_UNORM_PACK32:
-			return 4;
-		case DATA_FORMAT_D32_SFLOAT:
-			return 4;
-		case DATA_FORMAT_S8_UINT:
-			return 1;
-		case DATA_FORMAT_D16_UNORM_S8_UINT:
-			return 4;
-		case DATA_FORMAT_D24_UNORM_S8_UINT:
-			return 4;
-		case DATA_FORMAT_D32_SFLOAT_S8_UINT:
-			return 5; // ?
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-			return 1;
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			return 1;
-		case DATA_FORMAT_G8B8G8R8_422_UNORM:
-		case DATA_FORMAT_B8G8R8G8_422_UNORM:
-			return 4;
-		case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
-		case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM:
-		case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
-		case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM:
-		case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
-			return 4;
-		case DATA_FORMAT_R10X6_UNORM_PACK16:
-		case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16:
-		case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
-		case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
-		case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
-		case DATA_FORMAT_R12X4_UNORM_PACK16:
-		case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16:
-		case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
-		case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
-		case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
-		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
-			return 2;
-		case DATA_FORMAT_G16B16G16R16_422_UNORM:
-		case DATA_FORMAT_B16G16R16G16_422_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
-		case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
-		case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM:
-		case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
-			return 8;
-		default: {
-			ERR_PRINT("Format not handled, bug");
-		}
-	}
-
-	return 1;
-}
-
-// https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf
-
-void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: {
-			r_w = 4;
-			r_h = 4;
-		} break;
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: {
-			r_w = 4;
-			r_h = 4;
-		} break;
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
-			r_w = 8;
-			r_h = 8;
-		} break;
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			r_w = 4;
-			r_h = 4;
-			return;
-		default: {
-			r_w = 1;
-			r_h = 1;
-		}
-	}
-}
-
-uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_BC2_UNORM_BLOCK:
-		case DATA_FORMAT_BC2_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC3_UNORM_BLOCK:
-		case DATA_FORMAT_BC3_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-			return 8;
-		case DATA_FORMAT_BC5_UNORM_BLOCK:
-		case DATA_FORMAT_BC5_SNORM_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
-		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
-			return 16;
-		case DATA_FORMAT_BC7_UNORM_BLOCK:
-		case DATA_FORMAT_BC7_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-			return 8;
-		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
-			return 16;
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-			return 8;
-		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
-			return 16;
-		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
-		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
-		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
-			return 16;
-		default: {
-		}
-	}
-	return 1;
-}
-
-uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1.
-		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
-		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
-		case DATA_FORMAT_BC4_UNORM_BLOCK:
-		case DATA_FORMAT_BC4_SNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
-		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
-		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
-		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
-			return 1;
-		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
-		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: {
-			return 2;
-		}
-		default: {
-		}
-	}
-
-	return 0;
-}
-
-bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) {
-	switch (p_format) {
-		case DATA_FORMAT_S8_UINT:
-		case DATA_FORMAT_D16_UNORM_S8_UINT:
-		case DATA_FORMAT_D24_UNORM_S8_UINT:
-		case DATA_FORMAT_D32_SFLOAT_S8_UINT: {
-			return true;
-		}
-		default: {
-		}
-	}
-	return false;
-}
-
-uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) {
-	ERR_FAIL_COND_V(p_mipmaps == 0, 0);
-	uint32_t w = p_width;
-	uint32_t h = p_height;
-	uint32_t d = p_depth;
-
-	uint32_t size = 0;
-
-	uint32_t pixel_size = get_image_format_pixel_size(p_format);
-	uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format);
-	uint32_t blockw, blockh;
-	get_compressed_image_format_block_dimensions(p_format, blockw, blockh);
-
-	for (uint32_t i = 0; i < p_mipmaps; i++) {
-		uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w;
-		uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h;
-
-		uint32_t s = bw * bh;
-
-		s *= pixel_size;
-		s >>= pixel_rshift;
-		size += s * d;
-		if (r_blockw) {
-			*r_blockw = bw;
-		}
-		if (r_blockh) {
-			*r_blockh = bh;
-		}
-		if (r_depth) {
-			*r_depth = d;
-		}
-		w = MAX(blockw, w >> 1);
-		h = MAX(blockh, h >> 1);
-		d = MAX(1u, d >> 1);
-	}
-
-	return size;
-}
-
-uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
-	// Formats and block size don't really matter here since they can all go down to 1px (even if block is larger).
-	uint32_t w = p_width;
-	uint32_t h = p_height;
-	uint32_t d = p_depth;
-
-	uint32_t mipmaps = 1;
-
-	while (true) {
-		if (w == 1 && h == 1 && d == 1) {
-			break;
-		}
-
-		w = MAX(1u, w >> 1);
-		h = MAX(1u, h >> 1);
-		d = MAX(1u, d >> 1);
-
-		mipmaps++;
-	}
-
-	return mipmaps;
-}
-
-///////////////////////
-
-const VkCompareOp RenderingDeviceVulkan::compare_operators[RenderingDevice::COMPARE_OP_MAX] = {
-	VK_COMPARE_OP_NEVER,
-	VK_COMPARE_OP_LESS,
-	VK_COMPARE_OP_EQUAL,
-	VK_COMPARE_OP_LESS_OR_EQUAL,
-	VK_COMPARE_OP_GREATER,
-	VK_COMPARE_OP_NOT_EQUAL,
-	VK_COMPARE_OP_GREATER_OR_EQUAL,
-	VK_COMPARE_OP_ALWAYS
-};
-
-const VkStencilOp RenderingDeviceVulkan::stencil_operations[RenderingDevice::STENCIL_OP_MAX] = {
-	VK_STENCIL_OP_KEEP,
-	VK_STENCIL_OP_ZERO,
-	VK_STENCIL_OP_REPLACE,
-	VK_STENCIL_OP_INCREMENT_AND_CLAMP,
-	VK_STENCIL_OP_DECREMENT_AND_CLAMP,
-	VK_STENCIL_OP_INVERT,
-	VK_STENCIL_OP_INCREMENT_AND_WRAP,
-	VK_STENCIL_OP_DECREMENT_AND_WRAP
-};
-
-const VkSampleCountFlagBits RenderingDeviceVulkan::rasterization_sample_count[RenderingDevice::TEXTURE_SAMPLES_MAX] = {
-	VK_SAMPLE_COUNT_1_BIT,
-	VK_SAMPLE_COUNT_2_BIT,
-	VK_SAMPLE_COUNT_4_BIT,
-	VK_SAMPLE_COUNT_8_BIT,
-	VK_SAMPLE_COUNT_16_BIT,
-	VK_SAMPLE_COUNT_32_BIT,
-	VK_SAMPLE_COUNT_64_BIT,
-};
-
-const VkLogicOp RenderingDeviceVulkan::logic_operations[RenderingDevice::LOGIC_OP_MAX] = {
-	VK_LOGIC_OP_CLEAR,
-	VK_LOGIC_OP_AND,
-	VK_LOGIC_OP_AND_REVERSE,
-	VK_LOGIC_OP_COPY,
-	VK_LOGIC_OP_AND_INVERTED,
-	VK_LOGIC_OP_NO_OP,
-	VK_LOGIC_OP_XOR,
-	VK_LOGIC_OP_OR,
-	VK_LOGIC_OP_NOR,
-	VK_LOGIC_OP_EQUIVALENT,
-	VK_LOGIC_OP_INVERT,
-	VK_LOGIC_OP_OR_REVERSE,
-	VK_LOGIC_OP_COPY_INVERTED,
-	VK_LOGIC_OP_OR_INVERTED,
-	VK_LOGIC_OP_NAND,
-	VK_LOGIC_OP_SET
-};
-
-const VkBlendFactor RenderingDeviceVulkan::blend_factors[RenderingDevice::BLEND_FACTOR_MAX] = {
-	VK_BLEND_FACTOR_ZERO,
-	VK_BLEND_FACTOR_ONE,
-	VK_BLEND_FACTOR_SRC_COLOR,
-	VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
-	VK_BLEND_FACTOR_DST_COLOR,
-	VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
-	VK_BLEND_FACTOR_SRC_ALPHA,
-	VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
-	VK_BLEND_FACTOR_DST_ALPHA,
-	VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
-	VK_BLEND_FACTOR_CONSTANT_COLOR,
-	VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
-	VK_BLEND_FACTOR_CONSTANT_ALPHA,
-	VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
-	VK_BLEND_FACTOR_SRC_ALPHA_SATURATE,
-	VK_BLEND_FACTOR_SRC1_COLOR,
-	VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
-	VK_BLEND_FACTOR_SRC1_ALPHA,
-	VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA
-};
-const VkBlendOp RenderingDeviceVulkan::blend_operations[RenderingDevice::BLEND_OP_MAX] = {
-	VK_BLEND_OP_ADD,
-	VK_BLEND_OP_SUBTRACT,
-	VK_BLEND_OP_REVERSE_SUBTRACT,
-	VK_BLEND_OP_MIN,
-	VK_BLEND_OP_MAX
-};
-
-const VkSamplerAddressMode RenderingDeviceVulkan::address_modes[RenderingDevice::SAMPLER_REPEAT_MODE_MAX] = {
-	VK_SAMPLER_ADDRESS_MODE_REPEAT,
-	VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
-	VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
-	VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
-	VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE
-};
-
-const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice::SAMPLER_BORDER_COLOR_MAX] = {
-	VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
-	VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
-	VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
-	VK_BORDER_COLOR_INT_OPAQUE_BLACK,
-	VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
-	VK_BORDER_COLOR_INT_OPAQUE_WHITE
-};
-
-const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXTURE_TYPE_MAX] = {
-	VK_IMAGE_TYPE_1D,
-	VK_IMAGE_TYPE_2D,
-	VK_IMAGE_TYPE_3D,
-	VK_IMAGE_TYPE_2D,
-	VK_IMAGE_TYPE_1D,
-	VK_IMAGE_TYPE_2D,
-	VK_IMAGE_TYPE_2D
-};
-
-/***************************/
-/**** BUFFER MANAGEMENT ****/
-/***************************/
-
-Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mem_usage, VmaAllocationCreateFlags p_mem_flags) {
-	VkBufferCreateInfo bufferInfo;
-	bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
-	bufferInfo.pNext = nullptr;
-	bufferInfo.flags = 0;
-	bufferInfo.size = p_size;
-	bufferInfo.usage = p_usage;
-	bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-	bufferInfo.queueFamilyIndexCount = 0;
-	bufferInfo.pQueueFamilyIndices = nullptr;
-
-	VmaAllocationCreateInfo allocInfo;
-	allocInfo.flags = p_mem_flags;
-	allocInfo.usage = p_mem_usage;
-	allocInfo.requiredFlags = 0;
-	allocInfo.preferredFlags = 0;
-	allocInfo.memoryTypeBits = 0;
-	allocInfo.pool = nullptr;
-	allocInfo.pUserData = nullptr;
-	if (p_mem_usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) {
-		allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
-	}
-	if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
-		uint32_t mem_type_index = 0;
-		vmaFindMemoryTypeIndexForBufferInfo(allocator, &bufferInfo, &allocInfo, &mem_type_index);
-		allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index);
-	}
-
-	VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, nullptr);
-	ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + ".");
-	p_buffer->size = p_size;
-	p_buffer->buffer_info.buffer = p_buffer->buffer;
-	p_buffer->buffer_info.offset = 0;
-	p_buffer->buffer_info.range = p_size;
-	p_buffer->usage = p_usage;
-
-	buffer_memory += p_size;
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) {
-	ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER);
-
-	buffer_memory -= p_buffer->size;
-	vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation);
-	p_buffer->buffer = VK_NULL_HANDLE;
-	p_buffer->allocation = nullptr;
-	p_buffer->size = 0;
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_insert_staging_block() {
-	VkBufferCreateInfo bufferInfo;
-	bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
-	bufferInfo.pNext = nullptr;
-	bufferInfo.flags = 0;
-	bufferInfo.size = staging_buffer_block_size;
-	bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
-	bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-	bufferInfo.queueFamilyIndexCount = 0;
-	bufferInfo.pQueueFamilyIndices = nullptr;
-
-	VmaAllocationCreateInfo allocInfo;
-	allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
-	allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
-	allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
-	allocInfo.preferredFlags = 0;
-	allocInfo.memoryTypeBits = 0;
-	allocInfo.pool = nullptr;
-	allocInfo.pUserData = nullptr;
-
-	StagingBufferBlock block;
-
-	VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, nullptr);
-	ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vmaCreateBuffer failed with error " + itos(err) + ".");
-
-	block.frame_used = 0;
-	block.fill_amount = 0;
-
-	staging_buffer_blocks.insert(staging_buffer_current, block);
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) {
-	// Determine a block to use.
-
-	r_alloc_size = p_amount;
-
-	while (true) {
-		r_alloc_offset = 0;
-
-		// See if we can use current block.
-		if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
-			// We used this block this frame, let's see if there is still room.
-
-			uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount;
-
-			{
-				uint32_t align_remainder = write_from % p_required_align;
-				if (align_remainder != 0) {
-					write_from += p_required_align - align_remainder;
-				}
-			}
-
-			int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from);
-
-			if ((int32_t)p_amount < available_bytes) {
-				// All is good, we should be ok, all will fit.
-				r_alloc_offset = write_from;
-			} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {
-				// Ok all won't fit but at least we can fit a chunkie.
-				// All is good, update what needs to be written to.
-				r_alloc_offset = write_from;
-				r_alloc_size = available_bytes - (available_bytes % p_required_align);
-
-			} else {
-				// Can't fit it into this buffer.
-				// Will need to try next buffer.
-
-				staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
-
-				// Before doing anything, though, let's check that we didn't manage to fill all blocks.
-				// Possible in a single frame.
-				if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
-					// Guess we did.. ok, let's see if we can insert a new block.
-					if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
-						// We can, so we are safe.
-						Error err = _insert_staging_block();
-						if (err) {
-							return err;
-						}
-						// Claim for this frame.
-						staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-					} else {
-						// Ok, worst case scenario, all the staging buffers belong to this frame
-						// and this frame is not even done.
-						// If this is the main thread, it means the user is likely loading a lot of resources at once,.
-						// Otherwise, the thread should just be blocked until the next frame (currently unimplemented).
-
-						if (false) { // Separate thread from render.
-
-							//block_until_next_frame()
-							continue;
-						} else {
-							// Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
-							_flush(true);
-
-							// Clear the whole staging buffer.
-							for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-								staging_buffer_blocks.write[i].frame_used = 0;
-								staging_buffer_blocks.write[i].fill_amount = 0;
-							}
-							// Claim current.
-							staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-						}
-					}
-
-				} else {
-					// Not from current frame, so continue and try again.
-					continue;
-				}
-			}
-
-		} else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) {
-			// This is an old block, which was already processed, let's reuse.
-			staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-			staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
-		} else {
-			// This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
-			if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
-				// We are still allowed to create a new block, so let's do that and insert it for current pos.
-				Error err = _insert_staging_block();
-				if (err) {
-					return err;
-				}
-				// Claim for this frame.
-				staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-			} else {
-				// Oops, we are out of room and we can't create more.
-				// Let's flush older frames.
-				// The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway.
-				// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).
-
-				if (false) {
-					// Separate thread from render.
-					//block_until_next_frame()
-					continue; // And try again.
-				} else {
-					_flush(false);
-
-					for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-						// Clear all blocks but the ones from this frame.
-						int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
-						if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
-							break; // Ok, we reached something from this frame, abort.
-						}
-
-						staging_buffer_blocks.write[block_idx].frame_used = 0;
-						staging_buffer_blocks.write[block_idx].fill_amount = 0;
-					}
-
-					// Claim for current frame.
-					staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
-				}
-			}
-		}
-
-		// All was good, break.
-		break;
-	}
-
-	staging_buffer_used = true;
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) {
-	// Submitting may get chunked for various reasons, so convert this to a task.
-	size_t to_submit = p_data_size;
-	size_t submit_from = 0;
-
-	while (to_submit > 0) {
-		uint32_t block_write_offset;
-		uint32_t block_write_amount;
-
-		Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount);
-		if (err) {
-			return err;
-		}
-
-		// Map staging buffer (It's CPU and coherent).
-
-		void *data_ptr = nullptr;
-		{
-			VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
-			ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
-		}
-
-		// Copy to staging buffer.
-		memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
-
-		// Unmap.
-		vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
-		// Insert a command to copy this.
-
-		VkBufferCopy region;
-		region.srcOffset = block_write_offset;
-		region.dstOffset = submit_from + p_offset;
-		region.size = block_write_amount;
-
-		vkCmdCopyBuffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, p_buffer->buffer, 1, &region);
-
-		staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount;
-
-		to_submit -= block_write_amount;
-		submit_from += block_write_amount;
-	}
-
-	return OK;
-}
-
-void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) {
-	VkMemoryBarrier mem_barrier;
-	mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-	mem_barrier.pNext = nullptr;
-	mem_barrier.srcAccessMask = p_src_access;
-	mem_barrier.dstAccessMask = p_dst_access;
-
-	if (p_src_stage_mask == 0 || p_dst_stage_mask == 0) {
-		return; // No barrier, since this is invalid.
-	}
-	vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, nullptr, 0, nullptr);
-}
-
-void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
-	// Used for debug.
-	_memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
-			VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
-					VK_ACCESS_INDEX_READ_BIT |
-					VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
-					VK_ACCESS_UNIFORM_READ_BIT |
-					VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
-					VK_ACCESS_SHADER_READ_BIT |
-					VK_ACCESS_SHADER_WRITE_BIT |
-					VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
-					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-					VK_ACCESS_TRANSFER_READ_BIT |
-					VK_ACCESS_TRANSFER_WRITE_BIT |
-					VK_ACCESS_HOST_READ_BIT |
-					VK_ACCESS_HOST_WRITE_BIT,
-			VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
-					VK_ACCESS_INDEX_READ_BIT |
-					VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
-					VK_ACCESS_UNIFORM_READ_BIT |
-					VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
-					VK_ACCESS_SHADER_READ_BIT |
-					VK_ACCESS_SHADER_WRITE_BIT |
-					VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
-					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-					VK_ACCESS_TRANSFER_READ_BIT |
-					VK_ACCESS_TRANSFER_WRITE_BIT |
-					VK_ACCESS_HOST_READ_BIT |
-					VK_ACCESS_HOST_WRITE_BIT,
-			p_sync_with_draw);
-}
-
-void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) {
-	VkBufferMemoryBarrier buffer_mem_barrier;
-	buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
-	buffer_mem_barrier.pNext = nullptr;
-	buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-	buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-	buffer_mem_barrier.srcAccessMask = p_src_access;
-	buffer_mem_barrier.dstAccessMask = p_dst_access;
-	buffer_mem_barrier.buffer = buffer;
-	buffer_mem_barrier.offset = p_from;
-	buffer_mem_barrier.size = p_size;
-
-	vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, nullptr, 1, &buffer_mem_barrier, 0, nullptr);
-}
-
-/*****************/
-/**** TEXTURE ****/
-/*****************/
-
-RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	VkImageCreateInfo image_create_info;
-	image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-	image_create_info.pNext = nullptr;
-	image_create_info.flags = 0;
-
-	VkImageFormatListCreateInfoKHR format_list_create_info; // Keep out of the if, needed for creation.
-	Vector<VkFormat> allowed_formats; // Keep out of the if, needed for creation.
-	if (p_format.shareable_formats.size()) {
-		image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
-
-		if (context->is_device_extension_enabled(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME)) {
-			for (int i = 0; i < p_format.shareable_formats.size(); i++) {
-				allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]);
-			}
-
-			format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
-			format_list_create_info.pNext = nullptr;
-			format_list_create_info.viewFormatCount = allowed_formats.size();
-			format_list_create_info.pViewFormats = allowed_formats.ptr();
-			image_create_info.pNext = &format_list_create_info;
-
-			ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(),
-					"If supplied a list of shareable formats, the current format must be present in the list");
-			ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(),
-					"If supplied a list of shareable formats, the current view format override must be present in the list");
-		}
-	}
-
-	if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) {
-		image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
-	}
-	/*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) {
-		image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
-	}*/
-
-	ERR_FAIL_INDEX_V(p_format.texture_type, TEXTURE_TYPE_MAX, RID());
-
-	image_create_info.imageType = vulkan_image_type[p_format.texture_type];
-
-	ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");
-
-	image_create_info.format = vulkan_formats[p_format.format];
-
-	image_create_info.extent.width = p_format.width;
-	if (image_create_info.imageType == VK_IMAGE_TYPE_3D || image_create_info.imageType == VK_IMAGE_TYPE_2D) {
-		ERR_FAIL_COND_V_MSG(p_format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures");
-		image_create_info.extent.height = p_format.height;
-	} else {
-		image_create_info.extent.height = 1;
-	}
-
-	if (image_create_info.imageType == VK_IMAGE_TYPE_3D) {
-		ERR_FAIL_COND_V_MSG(p_format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures");
-		image_create_info.extent.depth = p_format.depth;
-	} else {
-		image_create_info.extent.depth = 1;
-	}
-
-	ERR_FAIL_COND_V(p_format.mipmaps < 1, RID());
-
-	image_create_info.mipLevels = p_format.mipmaps;
-
-	if (p_format.texture_type == TEXTURE_TYPE_1D_ARRAY || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) {
-		ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(),
-				"Amount of layers must be equal or greater than 1 for arrays and cubemaps.");
-		ERR_FAIL_COND_V_MSG((p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(),
-				"Cubemap and cubemap array textures must provide a layer number that is multiple of 6");
-		image_create_info.arrayLayers = p_format.array_layers;
-	} else {
-		image_create_info.arrayLayers = 1;
-	}
-
-	ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID());
-
-	image_create_info.samples = _ensure_supported_sample_count(p_format.samples);
-	image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
-
-	// Usage.
-	image_create_info.usage = 0;
-
-	if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-	}
-	if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) {
-		image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-	}
-
-	image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-	image_create_info.queueFamilyIndexCount = 0;
-	image_create_info.pQueueFamilyIndices = nullptr;
-	image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-
-	uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth);
-
-	ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, RID(),
-			"Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ").");
-
-	if (p_data.size()) {
-		ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(),
-				"Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later");
-
-		int expected_images = image_create_info.arrayLayers;
-		ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(),
-				"Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ").");
-
-		for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) {
-			uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, image_create_info.mipLevels);
-			ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(),
-					"Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ").");
-		}
-	}
-
-	{
-		// Validate that this image is supported for the intended use.
-		VkFormatProperties properties;
-		vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties);
-		VkFormatFeatureFlags flags;
-
-		String format_text = "'" + String(named_formats[p_format.format]) + "'";
-
-		if (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) {
-			flags = properties.linearTilingFeatures;
-			format_text += " (with CPU read bit)";
-		} else {
-			flags = properties.optimalTilingFeatures;
-		}
-
-		if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture.");
-		}
-
-		if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment.");
-		}
-
-		if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");
-		}
-
-		if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image.");
-		}
-
-		if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");
-		}
-
-		// Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported.
-		if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && p_format.format != DATA_FORMAT_R8_UINT) {
-			ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as VRS attachment.");
-		}
-	}
-
-	// Some view validation.
-
-	if (p_view.format_override != DATA_FORMAT_MAX) {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-	}
-	ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());
-	ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());
-
-	// Allocate memory.
-
-	uint32_t width, height;
-	uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
-
-	VmaAllocationCreateInfo allocInfo;
-	allocInfo.flags = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0;
-	allocInfo.pool = nullptr;
-	allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
-	allocInfo.requiredFlags = 0;
-	allocInfo.preferredFlags = 0;
-	allocInfo.memoryTypeBits = 0;
-	allocInfo.pUserData = nullptr;
-	if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
-		uint32_t mem_type_index = 0;
-		vmaFindMemoryTypeIndexForImageInfo(allocator, &image_create_info, &allocInfo, &mem_type_index);
-		allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index);
-	}
-
-	Texture texture;
-
-	VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info);
-	ERR_FAIL_COND_V_MSG(err, RID(), "vmaCreateImage failed with error " + itos(err) + ".");
-	image_memory += texture.allocation_info.size;
-	texture.type = p_format.texture_type;
-	texture.format = p_format.format;
-	texture.width = image_create_info.extent.width;
-	texture.height = image_create_info.extent.height;
-	texture.depth = image_create_info.extent.depth;
-	texture.layers = image_create_info.arrayLayers;
-	texture.mipmaps = image_create_info.mipLevels;
-	texture.base_mipmap = 0;
-	texture.base_layer = 0;
-	texture.is_resolve_buffer = p_format.is_resolve_buffer;
-	texture.usage_flags = p_format.usage_bits;
-	texture.samples = p_format.samples;
-	texture.allowed_shared_formats = p_format.shareable_formats;
-
-	// Set base layout based on usage priority.
-
-	if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
-		// First priority, readable.
-		texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-	} else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) {
-		// Second priority, storage.
-
-		texture.layout = VK_IMAGE_LAYOUT_GENERAL;
-
-	} else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-		// Third priority, color or depth.
-
-		texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
-	} else if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
-	} else {
-		texture.layout = VK_IMAGE_LAYOUT_GENERAL;
-	}
-
-	if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
-		texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
-
-		if (format_has_stencil(p_format.format)) {
-			texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
-		}
-	} else {
-		texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
-		texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	texture.bound = false;
-
-	// Create view.
-
-	VkImageViewCreateInfo image_view_create_info;
-	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-	image_view_create_info.pNext = nullptr;
-	image_view_create_info.flags = 0;
-	image_view_create_info.image = texture.image;
-
-	static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
-		VK_IMAGE_VIEW_TYPE_1D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_3D,
-		VK_IMAGE_VIEW_TYPE_CUBE,
-		VK_IMAGE_VIEW_TYPE_1D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_2D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
-	};
-
-	image_view_create_info.viewType = view_types[p_format.texture_type];
-	if (p_view.format_override == DATA_FORMAT_MAX) {
-		image_view_create_info.format = image_create_info.format;
-	} else {
-		image_view_create_info.format = vulkan_formats[p_view.format_override];
-	}
-
-	static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		VK_COMPONENT_SWIZZLE_IDENTITY,
-		VK_COMPONENT_SWIZZLE_ZERO,
-		VK_COMPONENT_SWIZZLE_ONE,
-		VK_COMPONENT_SWIZZLE_R,
-		VK_COMPONENT_SWIZZLE_G,
-		VK_COMPONENT_SWIZZLE_B,
-		VK_COMPONENT_SWIZZLE_A
-	};
-
-	image_view_create_info.components.r = component_swizzles[p_view.swizzle_r];
-	image_view_create_info.components.g = component_swizzles[p_view.swizzle_g];
-	image_view_create_info.components.b = component_swizzles[p_view.swizzle_b];
-	image_view_create_info.components.a = component_swizzles[p_view.swizzle_a];
-
-	image_view_create_info.subresourceRange.baseMipLevel = 0;
-	image_view_create_info.subresourceRange.levelCount = image_create_info.mipLevels;
-	image_view_create_info.subresourceRange.baseArrayLayer = 0;
-	image_view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers;
-	if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-	} else {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
-
-	if (err) {
-		vmaDestroyImage(allocator, texture.image, texture.allocation);
-		ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
-	}
-
-	// Barrier to set layout.
-	{
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = 0;
-		image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
-		image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-		image_memory_barrier.newLayout = texture.layout;
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = texture.image;
-		image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = 0;
-		image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels;
-		image_memory_barrier.subresourceRange.baseArrayLayer = 0;
-		image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers;
-
-		vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-
-	if (p_data.size()) {
-		for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) {
-			_texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL_BARRIERS, true);
-		}
-	}
-	return id;
-}
-
-RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_texture = texture_owner.get_or_null(p_with_texture);
-	ERR_FAIL_NULL_V(src_texture, RID());
-
-	if (src_texture->owner.is_valid()) { // Ahh this is a share.
-		p_with_texture = src_texture->owner;
-		src_texture = texture_owner.get_or_null(src_texture->owner);
-		ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
-	}
-
-	// Create view.
-
-	Texture texture = *src_texture;
-
-	VkImageViewCreateInfo image_view_create_info;
-	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-	image_view_create_info.pNext = nullptr;
-	image_view_create_info.flags = 0;
-	image_view_create_info.image = texture.image;
-
-	static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
-		VK_IMAGE_VIEW_TYPE_1D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_3D,
-		VK_IMAGE_VIEW_TYPE_CUBE,
-		VK_IMAGE_VIEW_TYPE_1D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_2D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
-	};
-
-	image_view_create_info.viewType = view_types[texture.type];
-	if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
-		image_view_create_info.format = vulkan_formats[texture.format];
-	} else {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-
-		ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
-				"Format override is not in the list of allowed shareable formats for original texture.");
-		image_view_create_info.format = vulkan_formats[p_view.format_override];
-	}
-
-	static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		VK_COMPONENT_SWIZZLE_IDENTITY,
-		VK_COMPONENT_SWIZZLE_ZERO,
-		VK_COMPONENT_SWIZZLE_ONE,
-		VK_COMPONENT_SWIZZLE_R,
-		VK_COMPONENT_SWIZZLE_G,
-		VK_COMPONENT_SWIZZLE_B,
-		VK_COMPONENT_SWIZZLE_A
-	};
-
-	image_view_create_info.components.r = component_swizzles[p_view.swizzle_r];
-	image_view_create_info.components.g = component_swizzles[p_view.swizzle_g];
-	image_view_create_info.components.b = component_swizzles[p_view.swizzle_b];
-	image_view_create_info.components.a = component_swizzles[p_view.swizzle_a];
-
-	image_view_create_info.subresourceRange.baseMipLevel = 0;
-	image_view_create_info.subresourceRange.levelCount = texture.mipmaps;
-	image_view_create_info.subresourceRange.layerCount = texture.layers;
-	image_view_create_info.subresourceRange.baseArrayLayer = 0;
-
-	if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-	} else {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	VkImageViewUsageCreateInfo usage_info;
-	if (context->is_device_extension_enabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME)) {
-		// May need to make VK_KHR_maintenance2 mandatory and thus has Vulkan 1.1 be our minimum supported version
-		// if we require setting this information. Vulkan 1.0 may simply not care..
-
-		usage_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
-		usage_info.pNext = nullptr;
-		if (p_view.format_override != DATA_FORMAT_MAX) {
-			// Need to validate usage with vulkan.
-
-			usage_info.usage = 0;
-
-			if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
-				if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_STORAGE_BIT)) {
-					usage_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
-				}
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-				if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-					usage_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
-				}
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-			}
-			if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-			}
-
-			if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT) {
-				usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-			}
-
-			image_view_create_info.pNext = &usage_info;
-		}
-	}
-
-	VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
-	ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + ".");
-
-	texture.owner = p_with_texture;
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	_add_dependency(id, p_with_texture);
-
-	return id;
-}
-
-RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) {
-	_THREAD_SAFE_METHOD_
-	// This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this).
-	VkImage image = (VkImage)p_image;
-
-	Texture texture;
-	texture.image = image;
-	// If we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image?
-	// Also leave texture.allocation_info alone.
-	// We'll set texture.view later on.
-	texture.type = p_type;
-	texture.format = p_format;
-	texture.samples = p_samples;
-	texture.width = p_width;
-	texture.height = p_height;
-	texture.depth = p_depth;
-	texture.layers = p_layers;
-	texture.mipmaps = 1;
-	texture.usage_flags = p_flags;
-	texture.base_mipmap = 0;
-	texture.base_layer = 0;
-	texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
-	texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
-
-	// Set base layout based on usage priority.
-
-	if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
-		// First priority, readable.
-		texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-	} else if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
-		// Second priority, storage.
-
-		texture.layout = VK_IMAGE_LAYOUT_GENERAL;
-
-	} else if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-		// Third priority, color or depth.
-
-		texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
-	} else if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
-	} else {
-		texture.layout = VK_IMAGE_LAYOUT_GENERAL;
-	}
-
-	if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
-		texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
-
-		// if (format_has_stencil(p_format.format)) {
-		// 	texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
-		// }
-	} else {
-		texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
-		texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	// Create a view for us to use.
-
-	VkImageViewCreateInfo image_view_create_info;
-	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-	image_view_create_info.pNext = nullptr;
-	image_view_create_info.flags = 0;
-	image_view_create_info.image = texture.image;
-
-	static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
-		VK_IMAGE_VIEW_TYPE_1D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_3D,
-		VK_IMAGE_VIEW_TYPE_CUBE,
-		VK_IMAGE_VIEW_TYPE_1D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_2D_ARRAY,
-		VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
-	};
-
-	image_view_create_info.viewType = view_types[texture.type];
-	image_view_create_info.format = vulkan_formats[texture.format];
-
-	static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		VK_COMPONENT_SWIZZLE_IDENTITY,
-		VK_COMPONENT_SWIZZLE_ZERO,
-		VK_COMPONENT_SWIZZLE_ONE,
-		VK_COMPONENT_SWIZZLE_R,
-		VK_COMPONENT_SWIZZLE_G,
-		VK_COMPONENT_SWIZZLE_B,
-		VK_COMPONENT_SWIZZLE_A
-	};
-
-	// Hardcode for now, maybe make this settable from outside.
-	image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R];
-	image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G];
-	image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B];
-	image_view_create_info.components.a = component_swizzles[TEXTURE_SWIZZLE_A];
-
-	image_view_create_info.subresourceRange.baseMipLevel = 0;
-	image_view_create_info.subresourceRange.levelCount = texture.mipmaps;
-	image_view_create_info.subresourceRange.baseArrayLayer = 0;
-	image_view_create_info.subresourceRange.layerCount = texture.layers;
-	if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-	} else {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
-
-	if (err) {
-		// vmaDestroyImage(allocator, texture.image, texture.allocation);
-		ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
-	}
-
-	// Barrier to set layout.
-	{
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = 0;
-		image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
-		image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-		image_memory_barrier.newLayout = texture.layout;
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = texture.image;
-		image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = 0;
-		image_memory_barrier.subresourceRange.levelCount = texture.mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = 0;
-		image_memory_barrier.subresourceRange.layerCount = texture.layers;
-
-		vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-
-	return id;
-}
-
-RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type, uint32_t p_layers) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_texture = texture_owner.get_or_null(p_with_texture);
-	ERR_FAIL_NULL_V(src_texture, RID());
-
-	if (src_texture->owner.is_valid()) { // Ahh this is a share.
-		p_with_texture = src_texture->owner;
-		src_texture = texture_owner.get_or_null(src_texture->owner);
-		ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
-	}
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
-			"Can only create a cubemap slice from a cubemap or cubemap array mipmap");
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(),
-			"Can only create a 3D slice from a 3D texture");
-
-	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(),
-			"Can only create an array slice from a 2D array mipmap");
-
-	// Create view.
-
-	ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());
-	ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());
-	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID());
-
-	int slice_layers = 1;
-	if (p_layers != 0) {
-		ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays");
-		ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds");
-		slice_layers = p_layers;
-	} else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) {
-		ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice");
-		slice_layers = src_texture->layers;
-	} else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
-		slice_layers = 6;
-	}
-
-	Texture texture = *src_texture;
-	get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
-	texture.mipmaps = p_mipmaps;
-	texture.layers = slice_layers;
-	texture.base_mipmap = p_mipmap;
-	texture.base_layer = p_layer;
-
-	VkImageViewCreateInfo image_view_create_info;
-	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-	image_view_create_info.pNext = nullptr;
-	image_view_create_info.flags = 0;
-	image_view_create_info.image = texture.image;
-
-	static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
-		VK_IMAGE_VIEW_TYPE_1D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_1D,
-		VK_IMAGE_VIEW_TYPE_2D,
-		VK_IMAGE_VIEW_TYPE_2D,
-	};
-
-	image_view_create_info.viewType = view_types[texture.type];
-
-	if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
-		image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
-	} else if (p_slice_type == TEXTURE_SLICE_3D) {
-		image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D;
-	} else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) {
-		image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
-	}
-
-	if (p_slice_type == TEXTURE_SLICE_2D) {
-		texture.type = TEXTURE_TYPE_2D;
-	} else if (p_slice_type == TEXTURE_SLICE_3D) {
-		texture.type = TEXTURE_TYPE_3D;
-	}
-
-	if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
-		image_view_create_info.format = vulkan_formats[texture.format];
-	} else {
-		ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
-
-		ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
-				"Format override is not in the list of allowed shareable formats for original texture.");
-		image_view_create_info.format = vulkan_formats[p_view.format_override];
-	}
-
-	static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
-		VK_COMPONENT_SWIZZLE_IDENTITY,
-		VK_COMPONENT_SWIZZLE_ZERO,
-		VK_COMPONENT_SWIZZLE_ONE,
-		VK_COMPONENT_SWIZZLE_R,
-		VK_COMPONENT_SWIZZLE_G,
-		VK_COMPONENT_SWIZZLE_B,
-		VK_COMPONENT_SWIZZLE_A
-	};
-
-	image_view_create_info.components.r = component_swizzles[p_view.swizzle_r];
-	image_view_create_info.components.g = component_swizzles[p_view.swizzle_g];
-	image_view_create_info.components.b = component_swizzles[p_view.swizzle_b];
-	image_view_create_info.components.a = component_swizzles[p_view.swizzle_a];
-
-	if (p_slice_type == TEXTURE_SLICE_CUBEMAP) {
-		ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(),
-				"Specified layer is invalid for cubemap");
-		ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(),
-				"Specified layer must be a multiple of 6.");
-	}
-	image_view_create_info.subresourceRange.baseMipLevel = p_mipmap;
-	image_view_create_info.subresourceRange.levelCount = p_mipmaps;
-	image_view_create_info.subresourceRange.layerCount = slice_layers;
-	image_view_create_info.subresourceRange.baseArrayLayer = p_layer;
-
-	if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-	} else {
-		image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	}
-
-	VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
-	ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + ".");
-
-	texture.owner = p_with_texture;
-	RID id = texture_owner.make_rid(texture);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	_add_dependency(id, p_with_texture);
-
-	return id;
-}
-
-Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
-	return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false);
-}
-
-static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_unit_size) {
-	uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size;
-	uint32_t dst_offset = 0;
-	for (uint32_t y = p_src_h; y > 0; y--) {
-		uint8_t const *__restrict src = p_src + src_offset;
-		uint8_t *__restrict dst = p_dst + dst_offset;
-		for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) {
-			*dst = *src;
-			src++;
-			dst++;
-		}
-		src_offset += p_src_full_w * p_unit_size;
-		dst_offset += p_src_w * p_unit_size;
-	}
-}
-
-Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER,
-			"Updating textures is forbidden during creation of a draw or compute list");
-
-	Texture *texture = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);
-
-	if (texture->owner != RID()) {
-		p_texture = texture->owner;
-		texture = texture_owner.get_or_null(texture->owner);
-		ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.
-	}
-
-	ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
-			"Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture.");
-
-	ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
-			"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable.");
-
-	uint32_t layer_count = texture->layers;
-	if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		layer_count *= 6;
-	}
-	ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);
-
-	uint32_t width, height;
-	uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);
-	uint32_t required_size = image_size;
-	uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format);
-	if (required_align == 1) {
-		required_align = get_image_format_pixel_size(texture->format);
-	}
-	if ((required_align % 4) != 0) { // Alignment rules are really strange.
-		required_align *= 4;
-	}
-
-	ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER,
-			"Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ").");
-
-	uint32_t region_size = texture_upload_region_size_px;
-
-	const uint8_t *r = p_data.ptr();
-
-	VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer;
-
-	// Barrier to transfer.
-	{
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = 0;
-		image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-		image_memory_barrier.oldLayout = texture->layout;
-		image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = texture->image;
-		image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = 0;
-		image_memory_barrier.subresourceRange.levelCount = texture->mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
-		image_memory_barrier.subresourceRange.layerCount = 1;
-
-		vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	uint32_t mipmap_offset = 0;
-
-	uint32_t logic_width = texture->width;
-	uint32_t logic_height = texture->height;
-
-	for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {
-		uint32_t depth;
-		uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);
-
-		const uint8_t *read_ptr_mipmap = r + mipmap_offset;
-		image_size = image_total - mipmap_offset;
-
-		for (uint32_t z = 0; z < depth; z++) { // For 3D textures, depth may be > 0.
-
-			const uint8_t *read_ptr = read_ptr_mipmap + (image_size / depth) * z;
-
-			for (uint32_t y = 0; y < height; y += region_size) {
-				for (uint32_t x = 0; x < width; x += region_size) {
-					uint32_t region_w = MIN(region_size, width - x);
-					uint32_t region_h = MIN(region_size, height - y);
-
-					uint32_t region_logic_w = MIN(region_size, logic_width - x);
-					uint32_t region_logic_h = MIN(region_size, logic_height - y);
-
-					uint32_t pixel_size = get_image_format_pixel_size(texture->format);
-					uint32_t to_allocate = region_w * region_h * pixel_size;
-					to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format);
-
-					uint32_t alloc_offset, alloc_size;
-					Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false);
-					ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-					uint8_t *write_ptr;
-
-					{ // Map.
-						void *data_ptr = nullptr;
-						VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
-						ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
-						write_ptr = (uint8_t *)data_ptr;
-						write_ptr += alloc_offset;
-					}
-
-					uint32_t block_w, block_h;
-					get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);
-
-					ERR_FAIL_COND_V(region_w % block_w, ERR_BUG);
-					ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);
-
-					if (block_w != 1 || block_h != 1) {
-						// Compressed image (blocks).
-						// Must copy a block region.
-
-						uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);
-						// Re-create current variables in blocky format.
-						uint32_t xb = x / block_w;
-						uint32_t yb = y / block_h;
-						uint32_t wb = width / block_w;
-						//uint32_t hb = height / block_h;
-						uint32_t region_wb = region_w / block_w;
-						uint32_t region_hb = region_h / block_h;
-						_copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, block_size);
-					} else {
-						// Regular image (pixels).
-						// Must copy a pixel region.
-						_copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, pixel_size);
-					}
-
-					{ // Unmap.
-						vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
-					}
-
-					VkBufferImageCopy buffer_image_copy;
-					buffer_image_copy.bufferOffset = alloc_offset;
-					buffer_image_copy.bufferRowLength = 0; // Tightly packed.
-					buffer_image_copy.bufferImageHeight = 0; // Tightly packed.
-
-					buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask;
-					buffer_image_copy.imageSubresource.mipLevel = mm_i;
-					buffer_image_copy.imageSubresource.baseArrayLayer = p_layer;
-					buffer_image_copy.imageSubresource.layerCount = 1;
-
-					buffer_image_copy.imageOffset.x = x;
-					buffer_image_copy.imageOffset.y = y;
-					buffer_image_copy.imageOffset.z = z;
-
-					buffer_image_copy.imageExtent.width = region_logic_w;
-					buffer_image_copy.imageExtent.height = region_logic_h;
-					buffer_image_copy.imageExtent.depth = 1;
-
-					vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy);
-
-					staging_buffer_blocks.write[staging_buffer_current].fill_amount = alloc_offset + alloc_size;
-				}
-			}
-		}
-
-		mipmap_offset = image_total;
-		logic_width = MAX(1u, logic_width >> 1);
-		logic_height = MAX(1u, logic_height >> 1);
-	}
-
-	// Barrier to restore layout.
-	{
-		uint32_t barrier_flags = 0;
-		uint32_t access_flags = 0;
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-			barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-
-		if (barrier_flags == 0) {
-			barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-		}
-
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-		image_memory_barrier.dstAccessMask = access_flags;
-		image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		image_memory_barrier.newLayout = texture->layout;
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = texture->image;
-		image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = 0;
-		image_memory_barrier.subresourceRange.levelCount = texture->mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
-		image_memory_barrier.subresourceRange.layerCount = 1;
-
-		vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	if (texture->used_in_frame != frames_drawn) {
-		texture->used_in_raster = false;
-		texture->used_in_compute = false;
-		texture->used_in_frame = frames_drawn;
-	}
-	texture->used_in_transfer = true;
-
-	return OK;
-}
-
-Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d) {
-	uint32_t width, height, depth;
-	uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth);
-
-	Vector<uint8_t> image_data;
-	image_data.resize(image_size);
-
-	void *img_mem;
-	vmaMapMemory(allocator, p_allocation, &img_mem);
-
-	uint32_t blockw, blockh;
-	get_compressed_image_format_block_dimensions(tex->format, blockw, blockh);
-	uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format);
-	uint32_t pixel_size = get_image_format_pixel_size(tex->format);
-
-	{
-		uint8_t *w = image_data.ptrw();
-
-		uint32_t mipmap_offset = 0;
-		for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) {
-			uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth);
-
-			uint8_t *write_ptr_mipmap = w + mipmap_offset;
-			image_size = image_total - mipmap_offset;
-
-			VkImageSubresource image_sub_resorce;
-			image_sub_resorce.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			image_sub_resorce.arrayLayer = p_layer;
-			image_sub_resorce.mipLevel = mm_i;
-			VkSubresourceLayout layout;
-			vkGetImageSubresourceLayout(device, p_image, &image_sub_resorce, &layout);
-
-			for (uint32_t z = 0; z < depth; z++) {
-				uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth;
-				const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch;
-
-				if (block_size > 1) {
-					// Compressed.
-					uint32_t line_width = (block_size * (width / blockw));
-					for (uint32_t y = 0; y < height / blockh; y++) {
-						const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
-						uint8_t *wptr = write_ptr + y * line_width;
-
-						memcpy(wptr, rptr, line_width);
-					}
-
-				} else {
-					// Uncompressed.
-					for (uint32_t y = 0; y < height; y++) {
-						const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
-						uint8_t *wptr = write_ptr + y * pixel_size * width;
-						memcpy(wptr, rptr, (uint64_t)pixel_size * width);
-					}
-				}
-			}
-
-			mipmap_offset = image_total;
-		}
-	}
-
-	vmaUnmapMemory(allocator, p_allocation);
-
-	return image_data;
-}
-
-Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, Vector<uint8_t>());
-
-	ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),
-			"Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture.");
-	ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),
-			"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
-
-	uint32_t layer_count = tex->layers;
-	if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		layer_count *= 6;
-	}
-	ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>());
-
-	if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {
-		// Does not need anything fancy, map and read.
-		return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer);
-	} else {
-		// Compute total image size.
-		uint32_t width, height, depth;
-		uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth);
-
-		// Allocate buffer.
-		VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve.
-		Buffer tmp_buffer;
-		_buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
-
-		{ // Source image barrier.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = 0;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.oldLayout = tex->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = 0;
-			image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		uint32_t computed_w = tex->width;
-		uint32_t computed_h = tex->height;
-		uint32_t computed_d = tex->depth;
-
-		uint32_t prev_size = 0;
-		uint32_t offset = 0;
-		for (uint32_t i = 0; i < tex->mipmaps; i++) {
-			VkBufferImageCopy buffer_image_copy;
-
-			uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1);
-			uint32_t size = image_size - prev_size;
-			prev_size = image_size;
-
-			buffer_image_copy.bufferOffset = offset;
-			buffer_image_copy.bufferImageHeight = 0;
-			buffer_image_copy.bufferRowLength = 0;
-			buffer_image_copy.imageSubresource.aspectMask = tex->read_aspect_mask;
-			buffer_image_copy.imageSubresource.baseArrayLayer = p_layer;
-			buffer_image_copy.imageSubresource.layerCount = 1;
-			buffer_image_copy.imageSubresource.mipLevel = i;
-			buffer_image_copy.imageOffset.x = 0;
-			buffer_image_copy.imageOffset.y = 0;
-			buffer_image_copy.imageOffset.z = 0;
-			buffer_image_copy.imageExtent.width = computed_w;
-			buffer_image_copy.imageExtent.height = computed_h;
-			buffer_image_copy.imageExtent.depth = computed_d;
-
-			vkCmdCopyImageToBuffer(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer.buffer, 1, &buffer_image_copy);
-
-			computed_w = MAX(1u, computed_w >> 1);
-			computed_h = MAX(1u, computed_h >> 1);
-			computed_d = MAX(1u, computed_d >> 1);
-			offset += size;
-		}
-
-		{ // Restore src.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
-			if (tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
-				image_memory_barrier.dstAccessMask |= VK_ACCESS_SHADER_WRITE_BIT;
-			}
-			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			image_memory_barrier.newLayout = tex->layout;
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = 0;
-			image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		_flush(true);
-
-		void *buffer_mem;
-		VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem);
-		ERR_FAIL_COND_V_MSG(vkerr, Vector<uint8_t>(), "vmaMapMemory failed with error " + itos(vkerr) + ".");
-
-		Vector<uint8_t> buffer_data;
-		{
-			buffer_data.resize(buffer_size);
-			uint8_t *w = buffer_data.ptrw();
-			memcpy(w, buffer_mem, buffer_size);
-		}
-
-		vmaUnmapMemory(allocator, tmp_buffer.allocation);
-
-		_buffer_free(&tmp_buffer);
-
-		return buffer_data;
-	}
-}
-
-bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, false);
-	return tex->owner.is_valid();
-}
-
-bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) {
-	return texture_owner.owns(p_texture);
-}
-
-RD::TextureFormat RenderingDeviceVulkan::texture_get_format(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, TextureFormat());
-
-	TextureFormat tf;
-
-	tf.format = tex->format;
-	tf.width = tex->width;
-	tf.height = tex->height;
-	tf.depth = tex->depth;
-	tf.array_layers = tex->layers;
-	tf.mipmaps = tex->mipmaps;
-	tf.texture_type = tex->type;
-	tf.samples = tex->samples;
-	tf.usage_bits = tex->usage_flags;
-	tf.shareable_formats = tex->allowed_shared_formats;
-	tf.is_resolve_buffer = tex->is_resolve_buffer;
-
-	return tf;
-}
-
-Size2i RenderingDeviceVulkan::texture_size(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, Size2i());
-	return Size2i(tex->width, tex->height);
-}
-
-uint64_t RenderingDeviceVulkan::texture_get_native_handle(RID p_texture) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(tex, 0);
-
-	return (uint64_t)tex->image;
-}
-
-Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_from_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
-
-	uint32_t src_layer_count = src_tex->layers;
-	uint32_t src_width, src_height, src_depth;
-	get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth);
-	if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		src_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER);
-
-	Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
-	ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
-			"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
-	ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");
-
-	uint32_t dst_layer_count = dst_tex->layers;
-	uint32_t dst_width, dst_height, dst_depth;
-	get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth);
-	if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		dst_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER,
-			"Source and destination texture must be of the same type (color or depth).");
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-
-	{
-		// PRE Copy the image.
-
-		{ // Source.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = 0;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.oldLayout = src_tex->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = src_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-		{ // Dest.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = 0;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-			image_memory_barrier.oldLayout = dst_tex->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = dst_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		// COPY.
-
-		{
-			VkImageCopy image_copy_region;
-			image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask;
-			image_copy_region.srcSubresource.baseArrayLayer = p_src_layer;
-			image_copy_region.srcSubresource.layerCount = 1;
-			image_copy_region.srcSubresource.mipLevel = p_src_mipmap;
-			image_copy_region.srcOffset.x = p_from.x;
-			image_copy_region.srcOffset.y = p_from.y;
-			image_copy_region.srcOffset.z = p_from.z;
-
-			image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask;
-			image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer;
-			image_copy_region.dstSubresource.layerCount = 1;
-			image_copy_region.dstSubresource.mipLevel = p_dst_mipmap;
-			image_copy_region.dstOffset.x = p_to.x;
-			image_copy_region.dstOffset.y = p_to.y;
-			image_copy_region.dstOffset.z = p_to.z;
-
-			image_copy_region.extent.width = p_size.x;
-			image_copy_region.extent.height = p_size.y;
-			image_copy_region.extent.depth = p_size.z;
-
-			vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
-		}
-
-		// RESTORE LAYOUT for SRC and DST.
-
-		uint32_t barrier_flags = 0;
-		uint32_t access_flags = 0;
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-			barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-
-		if (barrier_flags == 0) {
-			barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-		}
-
-		{ // Restore src.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.dstAccessMask = access_flags;
-			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			image_memory_barrier.newLayout = src_tex->layout;
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = src_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		{ // Make dst readable.
-
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = access_flags;
-			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-			image_memory_barrier.newLayout = dst_tex->layout;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = dst_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-	}
-
-	if (dst_tex->used_in_frame != frames_drawn) {
-		dst_tex->used_in_raster = false;
-		dst_tex->used_in_compute = false;
-		dst_tex->used_in_frame = frames_drawn;
-	}
-	dst_tex->used_in_transfer = true;
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_from_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
-
-	ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)");
-	ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");
-
-	Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
-	ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
-			"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
-	ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");
-
-	ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture).");
-	ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");
-
-	ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format.");
-	ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destination textures must have the same dimensions.");
-
-	ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER,
-			"Source and destination texture must be of the same type (color or depth).");
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-
-	{
-		// PRE Copy the image.
-
-		{ // Source.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = 0;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.oldLayout = src_tex->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = src_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-		{ // Dest.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = 0;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-			image_memory_barrier.oldLayout = dst_tex->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = dst_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		// COPY.
-
-		{
-			VkImageResolve image_copy_region;
-			image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask;
-			image_copy_region.srcSubresource.baseArrayLayer = src_tex->base_layer;
-			image_copy_region.srcSubresource.layerCount = 1;
-			image_copy_region.srcSubresource.mipLevel = src_tex->base_mipmap;
-			image_copy_region.srcOffset.x = 0;
-			image_copy_region.srcOffset.y = 0;
-			image_copy_region.srcOffset.z = 0;
-
-			image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask;
-			image_copy_region.dstSubresource.baseArrayLayer = dst_tex->base_layer;
-			image_copy_region.dstSubresource.layerCount = 1;
-			image_copy_region.dstSubresource.mipLevel = dst_tex->base_mipmap;
-			image_copy_region.dstOffset.x = 0;
-			image_copy_region.dstOffset.y = 0;
-			image_copy_region.dstOffset.z = 0;
-
-			image_copy_region.extent.width = src_tex->width;
-			image_copy_region.extent.height = src_tex->height;
-			image_copy_region.extent.depth = src_tex->depth;
-
-			vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
-		}
-
-		// RESTORE LAYOUT for SRC and DST.
-
-		uint32_t barrier_flags = 0;
-		uint32_t access_flags = 0;
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-			barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-
-		if (barrier_flags == 0) {
-			barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-		}
-
-		{ // Restore src.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.dstAccessMask = access_flags;
-			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			image_memory_barrier.newLayout = src_tex->layout;
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = src_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-
-		{ // Make dst readable.
-
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = access_flags;
-			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-			image_memory_barrier.newLayout = dst_tex->layout;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = dst_tex->image;
-			image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = 1;
-			image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = 1;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-		}
-	}
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	Texture *src_tex = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
-			"Source texture can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to clear this texture.");
-
-	ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);
-
-	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
-			"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared.");
-
-	uint32_t src_layer_count = src_tex->layers;
-	if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
-		src_layer_count *= 6;
-	}
-
-	ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER);
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-
-	VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-
-	// NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner.)
-	const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-	constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT;
-	constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-	const VkAccessFlags valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access;
-
-	{ // Barrier from previous access with optional layout change (see clear_layout logic above).
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = valid_texture_access;
-		image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-		image_memory_barrier.oldLayout = src_tex->layout;
-		image_memory_barrier.newLayout = clear_layout;
-
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = src_tex->image;
-		image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
-		image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer;
-		image_memory_barrier.subresourceRange.layerCount = p_layers;
-
-		vkCmdPipelineBarrier(command_buffer, valid_texture_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	VkClearColorValue clear_color;
-	clear_color.float32[0] = p_color.r;
-	clear_color.float32[1] = p_color.g;
-	clear_color.float32[2] = p_color.b;
-	clear_color.float32[3] = p_color.a;
-
-	VkImageSubresourceRange range;
-	range.aspectMask = src_tex->read_aspect_mask;
-	range.baseArrayLayer = src_tex->base_layer + p_base_layer;
-	range.layerCount = p_layers;
-	range.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
-	range.levelCount = p_mipmaps;
-
-	vkCmdClearColorImage(command_buffer, src_tex->image, clear_layout, &clear_color, 1, &range);
-
-	{ // Barrier to post clear accesses (changing back the layout if needed).
-
-		uint32_t barrier_flags = 0;
-		uint32_t access_flags = 0;
-		if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-			barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-			barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-			barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-			access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-			barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-
-		if (barrier_flags == 0) {
-			barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-		}
-
-		VkImageMemoryBarrier image_memory_barrier;
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-		image_memory_barrier.dstAccessMask = access_flags;
-		image_memory_barrier.oldLayout = clear_layout;
-		image_memory_barrier.newLayout = src_tex->layout;
-
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = src_tex->image;
-		image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
-		image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer;
-		image_memory_barrier.subresourceRange.layerCount = p_layers;
-
-		vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-	}
-
-	if (src_tex->used_in_frame != frames_drawn) {
-		src_tex->used_in_raster = false;
-		src_tex->used_in_compute = false;
-		src_tex->used_in_frame = frames_drawn;
-	}
-	src_tex->used_in_transfer = true;
-
-	return OK;
-}
-
-bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const {
-	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
-
-	_THREAD_SAFE_METHOD_
-
-	// Validate that this image is supported for the intended use.
-	VkFormatProperties properties;
-	vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
-	VkFormatFeatureFlags flags;
-
-	if (p_usage.has_flag(TEXTURE_USAGE_CPU_READ_BIT)) {
-		flags = properties.linearTilingFeatures;
-	} else {
-		flags = properties.optimalTilingFeatures;
-	}
-
-	if (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT) && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
-		return false;
-	}
-
-	if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
-		return false;
-	}
-
-	if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-		return false;
-	}
-
-	if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
-		return false;
-	}
-
-	if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
-		return false;
-	}
-
-	// Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported.
-	if (p_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && p_format != DATA_FORMAT_R8_UINT) {
-		return false;
-	}
-
-	return true;
-}
-
-/********************/
-/**** ATTACHMENT ****/
-/********************/
-
-VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) {
-	// Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them.
-	const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
-			VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
-			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148.
-			VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
-
-	VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
-	VkSubpassDependency2KHR dependencies[2] = {
-		{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0, 0 },
-		{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0, 0 }
-	};
-	VkSubpassDependency2KHR &dependency_from_external = dependencies[0];
-	VkSubpassDependency2KHR &dependency_to_external = dependencies[1];
-	LocalVector<int32_t> attachment_last_pass;
-	attachment_last_pass.resize(p_attachments.size());
-
-	if (p_view_count > 1) {
-		const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
-
-		// This only works with multiview!
-		ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported");
-
-		// Make sure we limit this to the number of views we support.
-		ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");
-	}
-
-	// These are only used if we use multiview but we need to define them in scope.
-	const uint32_t view_mask = (1 << p_view_count) - 1;
-	const uint32_t correlation_mask = (1 << p_view_count) - 1;
-
-	Vector<VkAttachmentDescription2KHR> attachments;
-	Vector<int> attachment_remap;
-
-	for (int i = 0; i < p_attachments.size(); i++) {
-		if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {
-			attachment_remap.push_back(VK_ATTACHMENT_UNUSED);
-			continue;
-		}
-
-		ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE);
-		ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE);
-		ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)),
-				VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");
-
-		VkAttachmentDescription2KHR description = {};
-		description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
-		description.pNext = nullptr;
-		description.flags = 0;
-		description.format = vulkan_formats[p_attachments[i].format];
-		description.samples = _ensure_supported_sample_count(p_attachments[i].samples);
-
-		bool is_sampled = p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT;
-		bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
-		bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
-		// We can setup a framebuffer where we write to our VRS texture to set it up.
-		// We make the assumption here that if our texture is actually used as our VRS attachment.
-		// It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
-		bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
-
-		if (is_vrs) {
-			// For VRS we only read, there is no writing to this texture.
-			description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-			description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-			description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-		} else {
-			// For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write.
-			// Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs
-			// the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
-			// stage.
-
-			switch (is_depth ? p_initial_depth_action : p_initial_action) {
-				case INITIAL_ACTION_CLEAR_REGION:
-				case INITIAL_ACTION_CLEAR: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-						description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-						description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-						dependency_from_external.srcStageMask |= reading_stages;
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						dependency_from_external.srcStageMask |= reading_stages;
-					}
-				} break;
-				case INITIAL_ACTION_KEEP: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-						description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-						description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-						dependency_from_external.srcStageMask |= reading_stages;
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						dependency_from_external.srcStageMask |= reading_stages;
-					}
-				} break;
-				case INITIAL_ACTION_DROP: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						dependency_from_external.srcStageMask |= reading_stages;
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						dependency_from_external.srcStageMask |= reading_stages;
-					}
-				} break;
-				case INITIAL_ACTION_CLEAR_REGION_CONTINUE:
-				case INITIAL_ACTION_CONTINUE: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-						description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-						description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						dependency_from_external.srcStageMask |= reading_stages;
-					}
-				} break;
-				default: {
-					ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
-				}
-			}
-		}
-
-		bool used_last = false;
-
-		{
-			int last_pass = p_passes.size() - 1;
-
-			if (is_depth) {
-				// Likely missing depth resolve?
-				if (p_passes[last_pass].depth_attachment == i) {
-					used_last = true;
-				}
-			} else if (is_vrs) {
-				if (p_passes[last_pass].vrs_attachment == i) {
-					used_last = true;
-				}
-			} else {
-				if (p_passes[last_pass].resolve_attachments.size()) {
-					// If using resolve attachments, check resolve attachments.
-					for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) {
-						if (p_passes[last_pass].resolve_attachments[j] == i) {
-							used_last = true;
-							break;
-						}
-					}
-				}
-				if (!used_last) {
-					for (int j = 0; j < p_passes[last_pass].color_attachments.size(); j++) {
-						if (p_passes[last_pass].color_attachments[j] == i) {
-							used_last = true;
-							break;
-						}
-					}
-				}
-			}
-
-			if (!used_last) {
-				for (int j = 0; j < p_passes[last_pass].preserve_attachments.size(); j++) {
-					if (p_passes[last_pass].preserve_attachments[j] == i) {
-						used_last = true;
-						break;
-					}
-				}
-			}
-		}
-
-		FinalAction final_action = p_final_action;
-		FinalAction final_depth_action = p_final_depth_action;
-
-		if (!used_last) {
-			if (is_depth) {
-				final_depth_action = FINAL_ACTION_DISCARD;
-
-			} else {
-				final_action = FINAL_ACTION_DISCARD;
-			}
-		}
-
-		if (is_vrs) {
-			// We don't change our VRS texture during this process.
-
-			description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-			description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-			description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-			// TODO: Do we need to update our external dependency?
-			// update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
-		} else {
-			switch (is_depth ? final_depth_action : final_action) {
-				case FINAL_ACTION_READ: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-						update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-						update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true);
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-						// TODO: What does this mean about the next usage (and thus appropriate dependency masks.
-					}
-				} break;
-				case FINAL_ACTION_DISCARD: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-					} else {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-					}
-				} break;
-				case FINAL_ACTION_CONTINUE: {
-					if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-					} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-					} else {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
-					}
-
-				} break;
-				default: {
-					ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
-				}
-			}
-		}
-
-		attachment_last_pass[i] = -1;
-		attachment_remap.push_back(attachments.size());
-		attachments.push_back(description);
-	}
-
-	LocalVector<VkSubpassDescription2KHR> subpasses;
-	LocalVector<LocalVector<VkAttachmentReference2KHR>> color_reference_array;
-	LocalVector<LocalVector<VkAttachmentReference2KHR>> input_reference_array;
-	LocalVector<LocalVector<VkAttachmentReference2KHR>> resolve_reference_array;
-	LocalVector<LocalVector<uint32_t>> preserve_reference_array;
-	LocalVector<VkAttachmentReference2KHR> depth_reference_array;
-	LocalVector<VkAttachmentReference2KHR> vrs_reference_array;
-	LocalVector<VkFragmentShadingRateAttachmentInfoKHR> vrs_attachment_info_array;
-
-	subpasses.resize(p_passes.size());
-	color_reference_array.resize(p_passes.size());
-	input_reference_array.resize(p_passes.size());
-	resolve_reference_array.resize(p_passes.size());
-	preserve_reference_array.resize(p_passes.size());
-	depth_reference_array.resize(p_passes.size());
-	vrs_reference_array.resize(p_passes.size());
-	vrs_attachment_info_array.resize(p_passes.size());
-
-	LocalVector<VkSubpassDependency2KHR> subpass_dependencies;
-
-	for (int i = 0; i < p_passes.size(); i++) {
-		const FramebufferPass *pass = &p_passes[i];
-
-		LocalVector<VkAttachmentReference2KHR> &color_references = color_reference_array[i];
-
-		TextureSamples texture_samples = TEXTURE_SAMPLES_1;
-		bool is_multisample_first = true;
-		void *subpass_nextptr = nullptr;
-
-		for (int j = 0; j < pass->color_attachments.size(); j++) {
-			int32_t attachment = pass->color_attachments[j];
-			VkAttachmentReference2KHR reference;
-			reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
-			reference.pNext = nullptr;
-			if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-				reference.attachment = VK_ATTACHMENT_UNUSED;
-				reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
-			} else {
-				ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as color attachment.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-
-				if (is_multisample_first) {
-					texture_samples = p_attachments[attachment].samples;
-					is_multisample_first = false;
-				} else {
-					ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples.");
-				}
-				reference.attachment = attachment_remap[attachment];
-				reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-				attachment_last_pass[attachment] = i;
-			}
-			reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			color_references.push_back(reference);
-		}
-
-		LocalVector<VkAttachmentReference2KHR> &input_references = input_reference_array[i];
-
-		for (int j = 0; j < pass->input_attachments.size(); j++) {
-			int32_t attachment = pass->input_attachments[j];
-			VkAttachmentReference2KHR reference;
-			reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
-			reference.pNext = nullptr;
-			if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-				reference.attachment = VK_ATTACHMENT_UNUSED;
-				reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
-			} else {
-				ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-				reference.attachment = attachment_remap[attachment];
-				reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-				attachment_last_pass[attachment] = i;
-			}
-			reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			input_references.push_back(reference);
-		}
-
-		LocalVector<VkAttachmentReference2KHR> &resolve_references = resolve_reference_array[i];
-
-		if (pass->resolve_attachments.size() > 0) {
-			ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ").");
-			ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, VK_NULL_HANDLE, "Resolve attachments specified, but color attachments are not multisample.");
-		}
-		for (int j = 0; j < pass->resolve_attachments.size(); j++) {
-			int32_t attachment = pass->resolve_attachments[j];
-			VkAttachmentReference2KHR reference;
-			reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
-			reference.pNext = nullptr;
-			if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
-				reference.attachment = VK_ATTACHMENT_UNUSED;
-				reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
-			} else {
-				ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");
-				ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused.");
-				ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture.");
-				ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-				bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;
-				ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
-				reference.attachment = attachment_remap[attachment];
-				reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
-				attachment_last_pass[attachment] = i;
-			}
-			reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			resolve_references.push_back(reference);
-		}
-
-		VkAttachmentReference2KHR &depth_stencil_reference = depth_reference_array[i];
-		depth_stencil_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
-		depth_stencil_reference.pNext = nullptr;
-
-		if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-			int32_t attachment = pass->depth_attachment;
-			ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");
-			ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment.");
-			ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-			depth_stencil_reference.attachment = attachment_remap[attachment];
-			depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-			depth_stencil_reference.aspectMask = VK_IMAGE_ASPECT_NONE;
-			attachment_last_pass[attachment] = i;
-
-			if (is_multisample_first) {
-				texture_samples = p_attachments[attachment].samples;
-				is_multisample_first = false;
-			} else {
-				ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth.");
-			}
-
-		} else {
-			depth_stencil_reference.attachment = VK_ATTACHMENT_UNUSED;
-			depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
-		}
-
-		if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
-			int32_t attachment = pass->vrs_attachment;
-			ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment.");
-			ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment.");
-			ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
-
-			VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i];
-			vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
-			vrs_reference.pNext = nullptr;
-			vrs_reference.attachment = attachment_remap[attachment];
-			vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
-			vrs_reference.aspectMask = VK_IMAGE_ASPECT_NONE;
-
-			Size2i texel_size = context->get_vrs_capabilities().texel_size;
-
-			VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i];
-			vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
-			vrs_attachment_info.pNext = nullptr;
-			vrs_attachment_info.pFragmentShadingRateAttachment = &vrs_reference;
-			vrs_attachment_info.shadingRateAttachmentTexelSize = { uint32_t(texel_size.x), uint32_t(texel_size.y) };
-
-			attachment_last_pass[attachment] = i;
-
-			subpass_nextptr = &vrs_attachment_info;
-		}
-
-		LocalVector<uint32_t> &preserve_references = preserve_reference_array[i];
-
-		for (int j = 0; j < pass->preserve_attachments.size(); j++) {
-			int32_t attachment = pass->preserve_attachments[j];
-
-			ERR_FAIL_COND_V_MSG(attachment == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + "). Preserve attachments can't be unused.");
-
-			ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");
-
-			if (attachment_last_pass[attachment] != i) {
-				// Preserve can still be used to keep depth or color from being discarded after use.
-				attachment_last_pass[attachment] = i;
-				preserve_references.push_back(attachment);
-			}
-		}
-
-		VkSubpassDescription2KHR &subpass = subpasses[i];
-		subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
-		subpass.pNext = subpass_nextptr;
-		subpass.flags = 0;
-		subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
-		if (p_view_count == 1) {
-			// VUID-VkSubpassDescription2-multiview-06558: If the multiview feature is not enabled, viewMask must be 0.
-			subpass.viewMask = 0;
-		} else {
-			subpass.viewMask = view_mask;
-		}
-		subpass.inputAttachmentCount = input_references.size();
-		if (input_references.size()) {
-			subpass.pInputAttachments = input_references.ptr();
-		} else {
-			subpass.pInputAttachments = nullptr;
-		}
-		subpass.colorAttachmentCount = color_references.size();
-		if (color_references.size()) {
-			subpass.pColorAttachments = color_references.ptr();
-		} else {
-			subpass.pColorAttachments = nullptr;
-		}
-		if (depth_stencil_reference.attachment != VK_ATTACHMENT_UNUSED) {
-			subpass.pDepthStencilAttachment = &depth_stencil_reference;
-		} else {
-			subpass.pDepthStencilAttachment = nullptr;
-		}
-
-		if (resolve_references.size()) {
-			subpass.pResolveAttachments = resolve_references.ptr();
-		} else {
-			subpass.pResolveAttachments = nullptr;
-		}
-
-		subpass.preserveAttachmentCount = preserve_references.size();
-		if (preserve_references.size()) {
-			subpass.pPreserveAttachments = preserve_references.ptr();
-		} else {
-			subpass.pPreserveAttachments = nullptr;
-		}
-
-		if (r_samples) {
-			r_samples->push_back(texture_samples);
-		}
-
-		if (i > 0) {
-			VkSubpassDependency2KHR dependency;
-			dependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
-			dependency.pNext = nullptr;
-			dependency.srcSubpass = i - 1;
-			dependency.dstSubpass = i;
-			dependency.srcStageMask = 0;
-			dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-			dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-
-			dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-			dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
-			dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
-			dependency.viewOffset = 0;
-			subpass_dependencies.push_back(dependency);
-		}
-		/*
-		// NOTE: Big Mallet Approach -- any layout transition causes a full barrier.
-		if (reference.layout != description.initialLayout) {
-			// NOTE: This should be smarter based on the texture's knowledge of its previous role.
-			dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
-			dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
-		}
-		if (reference.layout != description.finalLayout) {
-			// NOTE: This should be smarter based on the texture's knowledge of its subsequent role.
-			dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
-			dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
-		}
-		*/
-	}
-
-	VkRenderPassCreateInfo2KHR render_pass_create_info;
-	render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
-	render_pass_create_info.pNext = nullptr;
-	render_pass_create_info.flags = 0;
-
-	render_pass_create_info.attachmentCount = attachments.size();
-	render_pass_create_info.pAttachments = attachments.ptr();
-	render_pass_create_info.subpassCount = subpasses.size();
-	render_pass_create_info.pSubpasses = subpasses.ptr();
-	// Commenting this because it seems it just avoids raster and compute to work at the same time.
-	// Other barriers seem to be protecting the render pass fine.
-	//	render_pass_create_info.dependencyCount = 2;
-	//	render_pass_create_info.pDependencies = dependencies;
-
-	render_pass_create_info.dependencyCount = subpass_dependencies.size();
-	if (subpass_dependencies.size()) {
-		render_pass_create_info.pDependencies = subpass_dependencies.ptr();
-	} else {
-		render_pass_create_info.pDependencies = nullptr;
-	}
-
-	if (p_view_count == 1) {
-		// VUID-VkRenderPassCreateInfo2-viewMask-03057: If the VkSubpassDescription2::viewMask member of all elements of pSubpasses is 0, correlatedViewMaskCount must be 0.
-		render_pass_create_info.correlatedViewMaskCount = 0;
-		render_pass_create_info.pCorrelatedViewMasks = nullptr;
-	} else {
-		render_pass_create_info.correlatedViewMaskCount = 1;
-		render_pass_create_info.pCorrelatedViewMasks = &correlation_mask;
-	}
-
-	Vector<uint32_t> view_masks;
-	VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
-
-	if ((p_view_count > 1) && !context->supports_renderpass2()) {
-		// This is only required when using vkCreateRenderPass, we add it if vkCreateRenderPass2KHR is not supported
-		// resulting this in being passed to our vkCreateRenderPass fallback.
-
-		// Set view masks for each subpass.
-		for (uint32_t i = 0; i < subpasses.size(); i++) {
-			view_masks.push_back(view_mask);
-		}
-
-		render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
-		render_pass_multiview_create_info.pNext = nullptr;
-		render_pass_multiview_create_info.subpassCount = subpasses.size();
-		render_pass_multiview_create_info.pViewMasks = view_masks.ptr();
-		render_pass_multiview_create_info.dependencyCount = 0;
-		render_pass_multiview_create_info.pViewOffsets = nullptr;
-		render_pass_multiview_create_info.correlationMaskCount = 1;
-		render_pass_multiview_create_info.pCorrelationMasks = &correlation_mask;
-
-		render_pass_create_info.pNext = &render_pass_multiview_create_info;
-	}
-
-	VkRenderPass render_pass;
-	VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
-	ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass2KHR failed with error " + itos(res) + ".");
-
-	return render_pass;
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) {
-	FramebufferPass pass;
-	for (int i = 0; i < p_format.size(); i++) {
-		if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-			pass.depth_attachment = i;
-		} else {
-			pass.color_attachments.push_back(i);
-		}
-	}
-
-	Vector<FramebufferPass> passes;
-	passes.push_back(pass);
-	return framebuffer_format_create_multipass(p_format, passes, p_view_count);
-}
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	FramebufferFormatKey key;
-	key.attachments = p_attachments;
-	key.passes = p_passes;
-	key.view_count = p_view_count;
-
-	const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
-	if (E) {
-		// Exists, return.
-		return E->get();
-	}
-
-	Vector<TextureSamples> samples;
-	VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case.
-
-	if (render_pass == VK_NULL_HANDLE) { // Was likely invalid.
-		return INVALID_ID;
-	}
-	FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));
-
-	E = framebuffer_format_cache.insert(key, id);
-	FramebufferFormat fb_format;
-	fb_format.E = E;
-	fb_format.render_pass = render_pass;
-	fb_format.pass_samples = samples;
-	fb_format.view_count = p_view_count;
-	framebuffer_formats[id] = fb_format;
-	return id;
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_empty(TextureSamples p_samples) {
-	FramebufferFormatKey key;
-	key.passes.push_back(FramebufferPass());
-
-	const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
-	if (E) {
-		// Exists, return.
-		return E->get();
-	}
-
-	VkSubpassDescription2KHR subpass;
-	subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
-	subpass.pNext = nullptr;
-	subpass.flags = 0;
-	subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
-	subpass.viewMask = 0;
-	subpass.inputAttachmentCount = 0; // Unsupported for now.
-	subpass.pInputAttachments = nullptr;
-	subpass.colorAttachmentCount = 0;
-	subpass.pColorAttachments = nullptr;
-	subpass.pDepthStencilAttachment = nullptr;
-	subpass.pResolveAttachments = nullptr;
-	subpass.preserveAttachmentCount = 0;
-	subpass.pPreserveAttachments = nullptr;
-
-	VkRenderPassCreateInfo2KHR render_pass_create_info;
-	render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
-	render_pass_create_info.pNext = nullptr;
-	render_pass_create_info.flags = 0;
-	render_pass_create_info.attachmentCount = 0;
-	render_pass_create_info.pAttachments = nullptr;
-	render_pass_create_info.subpassCount = 1;
-	render_pass_create_info.pSubpasses = &subpass;
-	render_pass_create_info.dependencyCount = 0;
-	render_pass_create_info.pDependencies = nullptr;
-	render_pass_create_info.correlatedViewMaskCount = 0;
-	render_pass_create_info.pCorrelatedViewMasks = nullptr;
-
-	VkRenderPass render_pass;
-	VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
-
-	ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + ".");
-
-	if (render_pass == VK_NULL_HANDLE) { // Was likely invalid.
-		return INVALID_ID;
-	}
-
-	FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));
-
-	E = framebuffer_format_cache.insert(key, id);
-
-	FramebufferFormat fb_format;
-	fb_format.E = E;
-	fb_format.render_pass = render_pass;
-	fb_format.pass_samples.push_back(p_samples);
-	framebuffer_formats[id] = fb_format;
-	return id;
-}
-
-RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) {
-	HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format);
-	ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1);
-	ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1);
-
-	return E->value.pass_samples[p_pass];
-}
-
-/***********************/
-/**** RENDER TARGET ****/
-/***********************/
-
-RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples, FramebufferFormatID p_format_check) {
-	_THREAD_SAFE_METHOD_
-	Framebuffer framebuffer;
-	framebuffer.format_id = framebuffer_format_create_empty(p_samples);
-	ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());
-	framebuffer.size = p_size;
-	framebuffer.view_count = 1;
-
-	RID id = framebuffer_owner.make_rid(framebuffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	FramebufferPass pass;
-
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
-
-		ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
-
-		if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-			pass.depth_attachment = i;
-		} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
-			pass.vrs_attachment = i;
-		} else {
-			if (texture && texture->is_resolve_buffer) {
-				pass.resolve_attachments.push_back(i);
-			} else {
-				pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
-			}
-		}
-	}
-
-	Vector<FramebufferPass> passes;
-	passes.push_back(pass);
-
-	return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);
-}
-
-RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
-	_THREAD_SAFE_METHOD_
-
-	Vector<AttachmentFormat> attachments;
-	attachments.resize(p_texture_attachments.size());
-	Size2i size;
-	bool size_set = false;
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		AttachmentFormat af;
-		Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
-		if (!texture) {
-			af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;
-		} else {
-			ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
-
-			if (!size_set) {
-				size.width = texture->width;
-				size.height = texture->height;
-				size_set = true;
-			} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
-				// If this is not the first attachment we assume this is used as the VRS attachment.
-				// In this case this texture will be 1/16th the size of the color attachment.
-				// So we skip the size check.
-			} else {
-				ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
-						"All textures in a framebuffer should be the same size.");
-			}
-
-			af.format = texture->format;
-			af.samples = texture->samples;
-			af.usage_flags = texture->usage_flags;
-		}
-		attachments.write[i] = af;
-	}
-
-	ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");
-
-	FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count);
-	if (format_id == INVALID_ID) {
-		return RID();
-	}
-
-	ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(),
-			"The format used to check this framebuffer differs from the intended framebuffer format.");
-
-	Framebuffer framebuffer;
-	framebuffer.format_id = format_id;
-	framebuffer.texture_ids = p_texture_attachments;
-	framebuffer.size = size;
-	framebuffer.view_count = p_view_count;
-
-	RID id = framebuffer_owner.make_rid(framebuffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-
-	for (int i = 0; i < p_texture_attachments.size(); i++) {
-		if (p_texture_attachments[i].is_valid()) {
-			_add_dependency(id, p_texture_attachments[i]);
-		}
-	}
-
-	return id;
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_format(RID p_framebuffer) {
-	_THREAD_SAFE_METHOD_
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
-
-	return framebuffer->format_id;
-}
-
-bool RenderingDeviceVulkan::framebuffer_is_valid(RID p_framebuffer) const {
-	_THREAD_SAFE_METHOD_
-
-	return framebuffer_owner.owns(p_framebuffer);
-}
-
-void RenderingDeviceVulkan::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {
-	_THREAD_SAFE_METHOD_
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL(framebuffer);
-
-	framebuffer->invalidated_callback = p_callback;
-	framebuffer->invalidated_callback_userdata = p_userdata;
-}
-
-/*****************/
-/**** SAMPLER ****/
-/*****************/
-
-RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
-	_THREAD_SAFE_METHOD_
-
-	VkSamplerCreateInfo sampler_create_info;
-	sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
-	sampler_create_info.pNext = nullptr;
-	sampler_create_info.flags = 0;
-	sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
-	sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
-	sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
-
-	ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_create_info.addressModeU = address_modes[p_state.repeat_u];
-	ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_create_info.addressModeV = address_modes[p_state.repeat_v];
-	ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID());
-	sampler_create_info.addressModeW = address_modes[p_state.repeat_w];
-
-	sampler_create_info.mipLodBias = p_state.lod_bias;
-	sampler_create_info.anisotropyEnable = p_state.use_anisotropy && context->get_physical_device_features().samplerAnisotropy;
-	sampler_create_info.maxAnisotropy = p_state.anisotropy_max;
-	sampler_create_info.compareEnable = p_state.enable_compare;
-
-	ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID());
-	sampler_create_info.compareOp = compare_operators[p_state.compare_op];
-
-	sampler_create_info.minLod = p_state.min_lod;
-	sampler_create_info.maxLod = p_state.max_lod;
-
-	ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID());
-	sampler_create_info.borderColor = sampler_border_colors[p_state.border_color];
-
-	sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw;
-
-	VkSampler sampler;
-	VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler);
-	ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + ".");
-
-	RID id = sampler_owner.make_rid(sampler);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-bool RenderingDeviceVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {
-	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
-
-	_THREAD_SAFE_METHOD_
-
-	// Validate that this image is supported for the intended filtering.
-	VkFormatProperties properties;
-	vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
-
-	return p_sampler_filter == RD::SAMPLER_FILTER_NEAREST || (p_sampler_filter == RD::SAMPLER_FILTER_LINEAR && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT));
-}
-
-/**********************/
-/**** VERTEX ARRAY ****/
-/**********************/
-
-RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, bool p_use_as_storage) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	uint32_t usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
-	if (p_use_as_storage) {
-		usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
-	}
-	Buffer buffer;
-	_buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-		_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false);
-	}
-
-	RID id = vertex_buffer_owner.make_rid(buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
-RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) {
-	_THREAD_SAFE_METHOD_
-
-	VertexDescriptionKey key;
-	key.vertex_formats = p_vertex_formats;
-
-	VertexFormatID *idptr = vertex_format_cache.getptr(key);
-	if (idptr) {
-		return *idptr;
-	}
-
-	// Does not exist, create one and cache it.
-	VertexDescriptionCache vdcache;
-	vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size());
-	vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size());
-
-	HashSet<int> used_locations;
-	for (int i = 0; i < p_vertex_formats.size(); i++) {
-		ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX);
-		ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID);
-
-		ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID,
-				"Data format for attachment (" + itos(i) + "), '" + named_formats[p_vertex_formats[i].format] + "', is not valid for a vertex array.");
-
-		vdcache.bindings[i].binding = i;
-		vdcache.bindings[i].stride = p_vertex_formats[i].stride;
-		vdcache.bindings[i].inputRate = p_vertex_formats[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
-		vdcache.attributes[i].binding = i;
-		vdcache.attributes[i].location = p_vertex_formats[i].location;
-		vdcache.attributes[i].format = vulkan_formats[p_vertex_formats[i].format];
-		vdcache.attributes[i].offset = p_vertex_formats[i].offset;
-		used_locations.insert(p_vertex_formats[i].location);
-	}
-
-	vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-	vdcache.create_info.pNext = nullptr;
-	vdcache.create_info.flags = 0;
-
-	vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_formats.size();
-	vdcache.create_info.pVertexAttributeDescriptions = vdcache.attributes;
-
-	vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size();
-	vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings;
-	vdcache.vertex_formats = p_vertex_formats;
-
-	VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT);
-	vertex_format_cache[key] = id;
-	vertex_formats[id] = vdcache;
-	return id;
-}
-
-RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
-	const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
-
-	ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID());
-
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID());
-	}
-
-	VertexArray vertex_array;
-
-	if (p_offsets.is_empty()) {
-		vertex_array.offsets.resize_zeroed(p_src_buffers.size());
-	} else {
-		ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID());
-		vertex_array.offsets = p_offsets;
-	}
-
-	vertex_array.vertex_count = p_vertex_count;
-	vertex_array.description = p_vertex_format;
-	vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);
-
-		// Validate with buffer.
-		{
-			const VertexAttribute &atf = vd.vertex_formats[i];
-
-			uint32_t element_size = get_format_vertex_size(atf.format);
-			ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.
-
-			if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {
-				// Validate size for regular drawing.
-				uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;
-
-				ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),
-						"Attachment (" + itos(i) + ") will read past the end of the buffer.");
-
-			} else {
-				// Validate size for instances drawing.
-				uint64_t available = buffer->size - atf.offset;
-				ERR_FAIL_COND_V_MSG(available < element_size, RID(),
-						"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");
-
-				uint32_t instances_allowed = available / atf.stride;
-				vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed);
-			}
-		}
-
-		vertex_array.buffers.push_back(buffer->buffer);
-	}
-
-	RID id = vertex_array_owner.make_rid(vertex_array);
-	for (int i = 0; i < p_src_buffers.size(); i++) {
-		_add_dependency(id, p_src_buffers[i]);
-	}
-
-	return id;
-}
-
-RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector<uint8_t> &p_data, bool p_use_restart_indices) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_index_count == 0, RID());
-
-	IndexBuffer index_buffer;
-	index_buffer.index_type = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32;
-	index_buffer.supports_restart_indices = p_use_restart_indices;
-	index_buffer.index_count = p_index_count;
-	uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4);
-#ifdef DEBUG_ENABLED
-	if (p_data.size()) {
-		index_buffer.max_index = 0;
-		ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(),
-				"Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ").");
-		const uint8_t *r = p_data.ptr();
-		if (p_format == INDEX_BUFFER_FORMAT_UINT16) {
-			const uint16_t *index16 = (const uint16_t *)r;
-			for (uint32_t i = 0; i < p_index_count; i++) {
-				if (p_use_restart_indices && index16[i] == 0xFFFF) {
-					continue; // Restart index, ignore.
-				}
-				index_buffer.max_index = MAX(index16[i], index_buffer.max_index);
-			}
-		} else {
-			const uint32_t *index32 = (const uint32_t *)r;
-			for (uint32_t i = 0; i < p_index_count; i++) {
-				if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) {
-					continue; // Restart index, ignore.
-				}
-				index_buffer.max_index = MAX(index32[i], index_buffer.max_index);
-			}
-		}
-	} else {
-		index_buffer.max_index = 0xFFFFFFFF;
-	}
-#else
-	index_buffer.max_index = 0xFFFFFFFF;
-#endif
-	_buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&index_buffer, 0, r, data_size);
-		_buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false);
-	}
-	RID id = index_buffer_owner.make_rid(index_buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID());
-
-	IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_index_buffer);
-
-	ERR_FAIL_COND_V(p_index_count == 0, RID());
-	ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID());
-
-	IndexArray index_array;
-	index_array.max_index = index_buffer->max_index;
-	index_array.buffer = index_buffer->buffer;
-	index_array.offset = p_index_offset;
-	index_array.indices = p_index_count;
-	index_array.index_type = index_buffer->index_type;
-	index_array.supports_restart_indices = index_buffer->supports_restart_indices;
-
-	RID id = index_array_owner.make_rid(index_array);
-	_add_dependency(id, p_index_buffer);
-	return id;
-}
-
-/****************/
-/**** SHADER ****/
-/****************/
-
-static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = {
-	"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment"
-};
-
-static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MAX] = {
-	VK_SHADER_STAGE_VERTEX_BIT,
-	VK_SHADER_STAGE_FRAGMENT_BIT,
-	VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
-	VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
-	VK_SHADER_STAGE_COMPUTE_BIT,
-};
-
-String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
-	String ret;
-	const Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, String());
-	for (int i = 0; i < shader->sets.size(); i++) {
-		if (p_set >= 0 && i != p_set) {
-			continue;
-		}
-		for (int j = 0; j < shader->sets[i].uniform_info.size(); j++) {
-			const UniformInfo &ui = shader->sets[i].uniform_info[j];
-			if (!ret.is_empty()) {
-				ret += "\n";
-			}
-			ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length);
-		}
-	}
-	return ret;
-}
-
-// Version 1: initial.
-// Version 2: Added shader name.
-// Version 3: Added writable.
-// Version 4: 64-bit vertex input mask.
-
-#define SHADER_BINARY_VERSION 4
-
-String RenderingDeviceVulkan::shader_get_binary_cache_key() const {
-	return "Vulkan-SV" + itos(SHADER_BINARY_VERSION);
-}
-
-struct RenderingDeviceVulkanShaderBinaryDataBinding {
-	uint32_t type;
-	uint32_t binding;
-	uint32_t stages;
-	uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
-	uint32_t writable;
-};
-
-struct RenderingDeviceVulkanShaderBinarySpecializationConstant {
-	uint32_t type;
-	uint32_t constant_id;
-	union {
-		uint32_t int_value;
-		float float_value;
-		bool bool_value;
-	};
-	uint32_t stage_flags;
-};
-
-struct RenderingDeviceVulkanShaderBinaryData {
-	uint64_t vertex_input_mask;
-	uint32_t fragment_output_mask;
-	uint32_t specialization_constants_count;
-	uint32_t is_compute;
-	uint32_t compute_local_size[3];
-	uint32_t set_count;
-	uint32_t push_constant_size;
-	uint32_t push_constant_vk_stages_mask;
-	uint32_t stage_count;
-	uint32_t shader_name_len;
-};
-
-Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
-	SpirvReflectionData spirv_data;
-	if (_reflect_spirv(p_spirv, spirv_data) != OK) {
-		return Vector<uint8_t>();
-	}
-
-	ERR_FAIL_COND_V_MSG((uint32_t)spirv_data.uniforms.size() > limits.maxBoundDescriptorSets, Vector<uint8_t>(),
-			"Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
-
-	// Collect reflection data into binary data.
-	RenderingDeviceVulkanShaderBinaryData binary_data{};
-	Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
-	Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
-	{
-		binary_data.vertex_input_mask = spirv_data.vertex_input_mask;
-		binary_data.fragment_output_mask = spirv_data.fragment_output_mask;
-		binary_data.specialization_constants_count = spirv_data.specialization_constants.size();
-		binary_data.is_compute = spirv_data.is_compute;
-		binary_data.compute_local_size[0] = spirv_data.compute_local_size[0];
-		binary_data.compute_local_size[1] = spirv_data.compute_local_size[1];
-		binary_data.compute_local_size[2] = spirv_data.compute_local_size[2];
-		binary_data.set_count = spirv_data.uniforms.size();
-		binary_data.push_constant_size = spirv_data.push_constant_size;
-		for (uint32_t i = 0; i < SHADER_STAGE_MAX; i++) {
-			if (spirv_data.push_constant_stages_mask.has_flag((ShaderStage)(1 << i))) {
-				binary_data.push_constant_vk_stages_mask |= shader_stage_masks[i];
-			}
-		}
-
-		for (const Vector<SpirvReflectionData::Uniform> &spirv_set : spirv_data.uniforms) {
-			Vector<RenderingDeviceVulkanShaderBinaryDataBinding> set_bindings;
-			for (const SpirvReflectionData::Uniform &spirv_uniform : spirv_set) {
-				RenderingDeviceVulkanShaderBinaryDataBinding binding{};
-				binding.type = (uint32_t)spirv_uniform.type;
-				binding.binding = spirv_uniform.binding;
-				binding.stages = (uint32_t)spirv_uniform.stages_mask;
-				binding.length = spirv_uniform.length;
-				binding.writable = (uint32_t)spirv_uniform.writable;
-				set_bindings.push_back(binding);
-			}
-			uniform_info.push_back(set_bindings);
-		}
-
-		for (const SpirvReflectionData::SpecializationConstant &spirv_sc : spirv_data.specialization_constants) {
-			RenderingDeviceVulkanShaderBinarySpecializationConstant spec_constant{};
-			spec_constant.type = (uint32_t)spirv_sc.type;
-			spec_constant.constant_id = spirv_sc.constant_id;
-			spec_constant.int_value = spirv_sc.int_value;
-			spec_constant.stage_flags = (uint32_t)spirv_sc.stages_mask;
-			specialization_constants.push_back(spec_constant);
-		}
-	}
-
-	Vector<Vector<uint8_t>> compressed_stages;
-	Vector<uint32_t> smolv_size;
-	Vector<uint32_t> zstd_size; // If 0, zstd not used.
-
-	uint32_t stages_binary_size = 0;
-
-	bool strip_debug = false;
-
-	for (int i = 0; i < p_spirv.size(); i++) {
-		smolv::ByteArray smolv;
-		if (!smolv::Encode(p_spirv[i].spir_v.ptr(), p_spirv[i].spir_v.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) {
-			ERR_FAIL_V_MSG(Vector<uint8_t>(), "Error compressing shader stage :" + String(shader_stage_names[p_spirv[i].shader_stage]));
-		} else {
-			smolv_size.push_back(smolv.size());
-			{ // zstd.
-				Vector<uint8_t> zstd;
-				zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
-				int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
-
-				if (dst_size > 0 && (uint32_t)dst_size < smolv.size()) {
-					zstd_size.push_back(dst_size);
-					zstd.resize(dst_size);
-					compressed_stages.push_back(zstd);
-				} else {
-					Vector<uint8_t> smv;
-					smv.resize(smolv.size());
-					memcpy(smv.ptrw(), &smolv[0], smolv.size());
-					zstd_size.push_back(0); // Not using zstd.
-					compressed_stages.push_back(smv);
-				}
-			}
-		}
-		uint32_t s = compressed_stages[i].size();
-		if (s % 4 != 0) {
-			s += 4 - (s % 4);
-		}
-		stages_binary_size += s;
-	}
-
-	binary_data.specialization_constants_count = specialization_constants.size();
-	binary_data.set_count = uniform_info.size();
-	binary_data.stage_count = p_spirv.size();
-
-	CharString shader_name_utf = p_shader_name.utf8();
-
-	binary_data.shader_name_len = shader_name_utf.length();
-
-	uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
-	total_size += sizeof(RenderingDeviceVulkanShaderBinaryData);
-
-	total_size += binary_data.shader_name_len;
-
-	if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-		total_size += 4 - (binary_data.shader_name_len % 4);
-	}
-
-	for (int i = 0; i < uniform_info.size(); i++) {
-		total_size += sizeof(uint32_t);
-		total_size += uniform_info[i].size() * sizeof(RenderingDeviceVulkanShaderBinaryDataBinding);
-	}
-
-	total_size += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size();
-
-	total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
-	total_size += stages_binary_size;
-
-	Vector<uint8_t> ret;
-	ret.resize(total_size);
-	{
-		uint32_t offset = 0;
-		uint8_t *binptr = ret.ptrw();
-		binptr[0] = 'G';
-		binptr[1] = 'S';
-		binptr[2] = 'B';
-		binptr[3] = 'D'; // Godot Shader Binary Data.
-		offset += 4;
-		encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
-		offset += sizeof(uint32_t);
-		encode_uint32(sizeof(RenderingDeviceVulkanShaderBinaryData), binptr + offset);
-		offset += sizeof(uint32_t);
-		memcpy(binptr + offset, &binary_data, sizeof(RenderingDeviceVulkanShaderBinaryData));
-		offset += sizeof(RenderingDeviceVulkanShaderBinaryData);
-
-		if (binary_data.shader_name_len > 0) {
-			memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
-			offset += binary_data.shader_name_len;
-
-			if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-				offset += 4 - (binary_data.shader_name_len % 4);
-			}
-		}
-
-		for (int i = 0; i < uniform_info.size(); i++) {
-			int count = uniform_info[i].size();
-			encode_uint32(count, binptr + offset);
-			offset += sizeof(uint32_t);
-			if (count > 0) {
-				memcpy(binptr + offset, uniform_info[i].ptr(), sizeof(RenderingDeviceVulkanShaderBinaryDataBinding) * count);
-				offset += sizeof(RenderingDeviceVulkanShaderBinaryDataBinding) * count;
-			}
-		}
-
-		if (specialization_constants.size()) {
-			memcpy(binptr + offset, specialization_constants.ptr(), sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size());
-			offset += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size();
-		}
-
-		for (int i = 0; i < compressed_stages.size(); i++) {
-			encode_uint32(p_spirv[i].shader_stage, binptr + offset);
-			offset += sizeof(uint32_t);
-			encode_uint32(smolv_size[i], binptr + offset);
-			offset += sizeof(uint32_t);
-			encode_uint32(zstd_size[i], binptr + offset);
-			offset += sizeof(uint32_t);
-			memcpy(binptr + offset, compressed_stages[i].ptr(), compressed_stages[i].size());
-
-			uint32_t s = compressed_stages[i].size();
-
-			if (s % 4 != 0) {
-				s += 4 - (s % 4);
-			}
-
-			offset += s;
-		}
-
-		ERR_FAIL_COND_V(offset != (uint32_t)ret.size(), Vector<uint8_t>());
-	}
-
-	return ret;
-}
-
-RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) {
-	const uint8_t *binptr = p_shader_binary.ptr();
-	uint32_t binsize = p_shader_binary.size();
-
-	uint32_t read_offset = 0;
-	// Consistency check.
-	ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceVulkanShaderBinaryData), RID());
-	ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', RID());
-
-	uint32_t bin_version = decode_uint32(binptr + 4);
-	ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID());
-
-	uint32_t bin_data_size = decode_uint32(binptr + 8);
-
-	const RenderingDeviceVulkanShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinaryData *>(binptr + 12));
-
-	Shader::PushConstant push_constant;
-	push_constant.size = binary_data.push_constant_size;
-	push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask;
-
-	uint64_t vertex_input_mask = binary_data.vertex_input_mask;
-
-	uint32_t fragment_output_mask = binary_data.fragment_output_mask;
-
-	bool is_compute = binary_data.is_compute;
-
-	const uint32_t compute_local_size[3] = { binary_data.compute_local_size[0], binary_data.compute_local_size[1], binary_data.compute_local_size[2] };
-
-	read_offset += sizeof(uint32_t) * 3 + bin_data_size;
-
-	String name;
-
-	if (binary_data.shader_name_len) {
-		name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
-		read_offset += binary_data.shader_name_len;
-		if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
-			read_offset += 4 - (binary_data.shader_name_len % 4);
-		}
-	}
-
-	Vector<Vector<VkDescriptorSetLayoutBinding>> set_bindings;
-	Vector<Vector<UniformInfo>> uniform_info;
-
-	set_bindings.resize(binary_data.set_count);
-	uniform_info.resize(binary_data.set_count);
-
-	for (uint32_t i = 0; i < binary_data.set_count; i++) {
-		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, RID());
-		uint32_t set_count = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		const RenderingDeviceVulkanShaderBinaryDataBinding *set_ptr = reinterpret_cast<const RenderingDeviceVulkanShaderBinaryDataBinding *>(binptr + read_offset);
-		uint32_t set_size = set_count * sizeof(RenderingDeviceVulkanShaderBinaryDataBinding);
-		ERR_FAIL_COND_V(read_offset + set_size >= binsize, RID());
-
-		for (uint32_t j = 0; j < set_count; j++) {
-			UniformInfo info;
-			info.type = UniformType(set_ptr[j].type);
-			info.writable = set_ptr[j].writable;
-			info.length = set_ptr[j].length;
-			info.binding = set_ptr[j].binding;
-			info.stages = set_ptr[j].stages;
-
-			VkDescriptorSetLayoutBinding layout_binding;
-			layout_binding.pImmutableSamplers = nullptr;
-			layout_binding.binding = set_ptr[j].binding;
-			layout_binding.descriptorCount = 1;
-			layout_binding.stageFlags = 0;
-			for (uint32_t k = 0; k < SHADER_STAGE_MAX; k++) {
-				if (set_ptr[j].stages & (1 << k)) {
-					layout_binding.stageFlags |= shader_stage_masks[k];
-				}
-			}
-
-			switch (info.type) {
-				case UNIFORM_TYPE_SAMPLER: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
-					layout_binding.descriptorCount = set_ptr[j].length;
-				} break;
-				case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-					layout_binding.descriptorCount = set_ptr[j].length;
-				} break;
-				case UNIFORM_TYPE_TEXTURE: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
-					layout_binding.descriptorCount = set_ptr[j].length;
-				} break;
-				case UNIFORM_TYPE_IMAGE: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
-					layout_binding.descriptorCount = set_ptr[j].length;
-				} break;
-				case UNIFORM_TYPE_TEXTURE_BUFFER: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
-					layout_binding.descriptorCount = set_ptr[j].length;
-				} break;
-				case UNIFORM_TYPE_IMAGE_BUFFER: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
-				} break;
-				case UNIFORM_TYPE_UNIFORM_BUFFER: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-				} break;
-				case UNIFORM_TYPE_STORAGE_BUFFER: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
-				} break;
-				case UNIFORM_TYPE_INPUT_ATTACHMENT: {
-					layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
-				} break;
-				default: {
-					ERR_FAIL_V(RID());
-				}
-			}
-
-			set_bindings.write[i].push_back(layout_binding);
-			uniform_info.write[i].push_back(info);
-		}
-
-		read_offset += set_size;
-	}
-
-	ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID());
-
-	Vector<Shader::SpecializationConstant> specialization_constants;
-
-	for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
-		const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinarySpecializationConstant *>(binptr + read_offset));
-		Shader::SpecializationConstant sc;
-		sc.constant.int_value = src_sc.int_value;
-		sc.constant.type = PipelineSpecializationConstantType(src_sc.type);
-		sc.constant.constant_id = src_sc.constant_id;
-		sc.stage_flags = src_sc.stage_flags;
-		specialization_constants.push_back(sc);
-
-		read_offset += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant);
-	}
-
-	Vector<Vector<uint8_t>> stage_spirv_data;
-	Vector<ShaderStage> stage_type;
-
-	for (uint32_t i = 0; i < binary_data.stage_count; i++) {
-		ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, RID());
-		uint32_t stage = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		uint32_t smolv_size = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-		uint32_t zstd_size = decode_uint32(binptr + read_offset);
-		read_offset += sizeof(uint32_t);
-
-		uint32_t buf_size = (zstd_size > 0) ? zstd_size : smolv_size;
-
-		Vector<uint8_t> smolv;
-		const uint8_t *src_smolv = nullptr;
-
-		if (zstd_size > 0) {
-			// Decompress to smolv.
-			smolv.resize(smolv_size);
-			int dec_smolv_size = Compression::decompress(smolv.ptrw(), smolv.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
-			ERR_FAIL_COND_V(dec_smolv_size != (int32_t)smolv_size, RID());
-			src_smolv = smolv.ptr();
-		} else {
-			src_smolv = binptr + read_offset;
-		}
-
-		Vector<uint8_t> spirv;
-		uint32_t spirv_size = smolv::GetDecodedBufferSize(src_smolv, smolv_size);
-		spirv.resize(spirv_size);
-		if (!smolv::Decode(src_smolv, smolv_size, spirv.ptrw(), spirv_size)) {
-			ERR_FAIL_V_MSG(RID(), "Malformed smolv input uncompressing shader stage:" + String(shader_stage_names[stage]));
-		}
-		stage_spirv_data.push_back(spirv);
-		stage_type.push_back(ShaderStage(stage));
-
-		if (buf_size % 4 != 0) {
-			buf_size += 4 - (buf_size % 4);
-		}
-
-		ERR_FAIL_COND_V(read_offset + buf_size > binsize, RID());
-
-		read_offset += buf_size;
-	}
-
-	ERR_FAIL_COND_V(read_offset != binsize, RID());
-
-	// All good, let's create modules.
-
-	_THREAD_SAFE_METHOD_
-
-	RID id;
-	if (p_placeholder.is_null()) {
-		id = shader_owner.make_rid();
-	} else {
-		id = p_placeholder;
-	}
-
-	Shader *shader = shader_owner.get_or_null(id);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	shader->vertex_input_mask = vertex_input_mask;
-	shader->fragment_output_mask = fragment_output_mask;
-	shader->push_constant = push_constant;
-	shader->is_compute = is_compute;
-	shader->compute_local_size[0] = compute_local_size[0];
-	shader->compute_local_size[1] = compute_local_size[1];
-	shader->compute_local_size[2] = compute_local_size[2];
-	shader->specialization_constants = specialization_constants;
-	shader->name = name;
-
-	String error_text;
-
-	bool success = true;
-	for (int i = 0; i < stage_spirv_data.size(); i++) {
-		VkShaderModuleCreateInfo shader_module_create_info;
-		shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
-		shader_module_create_info.pNext = nullptr;
-		shader_module_create_info.flags = 0;
-		shader_module_create_info.codeSize = stage_spirv_data[i].size();
-		const uint8_t *r = stage_spirv_data[i].ptr();
-
-		shader_module_create_info.pCode = (const uint32_t *)r;
-
-		VkShaderModule module;
-		VkResult res = vkCreateShaderModule(device, &shader_module_create_info, nullptr, &module);
-		if (res) {
-			success = false;
-			error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(shader_stage_names[stage_type[i]]);
-			break;
-		}
-
-		VkPipelineShaderStageCreateInfo shader_stage;
-		shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-		shader_stage.pNext = nullptr;
-		shader_stage.flags = 0;
-		shader_stage.stage = shader_stage_masks[stage_type[i]];
-		shader_stage.module = module;
-		shader_stage.pName = "main";
-		shader_stage.pSpecializationInfo = nullptr;
-
-		shader->pipeline_stages.push_back(shader_stage);
-	}
-	// Proceed to create descriptor sets.
-
-	if (success) {
-		for (int i = 0; i < set_bindings.size(); i++) {
-			// Empty ones are fine if they were not used according to spec (binding count will be 0).
-			VkDescriptorSetLayoutCreateInfo layout_create_info;
-			layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
-			layout_create_info.pNext = nullptr;
-			layout_create_info.flags = 0;
-			layout_create_info.bindingCount = set_bindings[i].size();
-			layout_create_info.pBindings = set_bindings[i].ptr();
-
-			VkDescriptorSetLayout layout;
-			VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, nullptr, &layout);
-			if (res) {
-				error_text = "Error (" + itos(res) + ") creating descriptor set layout for set " + itos(i);
-				success = false;
-				break;
-			}
-
-			Shader::Set set;
-			set.descriptor_set_layout = layout;
-			set.uniform_info = uniform_info[i];
-			// Sort and hash.
-			set.uniform_info.sort();
-
-			uint32_t format = 0; // No format, default.
-
-			if (set.uniform_info.size()) {
-				// Has data, needs an actual format.
-				UniformSetFormat usformat;
-				usformat.uniform_info = set.uniform_info;
-				RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);
-				if (E) {
-					format = E->get();
-				} else {
-					format = uniform_set_format_cache.size() + 1;
-					uniform_set_format_cache.insert(usformat, format);
-				}
-			}
-
-			shader->sets.push_back(set);
-			shader->set_formats.push_back(format);
-		}
-	}
-
-	if (success) {
-		// Create pipeline layout.
-		VkPipelineLayoutCreateInfo pipeline_layout_create_info;
-		pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
-		pipeline_layout_create_info.pNext = nullptr;
-		pipeline_layout_create_info.flags = 0;
-		pipeline_layout_create_info.setLayoutCount = shader->sets.size();
-
-		Vector<VkDescriptorSetLayout> layouts;
-		layouts.resize(shader->sets.size());
-
-		for (int i = 0; i < layouts.size(); i++) {
-			layouts.write[i] = shader->sets[i].descriptor_set_layout;
-		}
-
-		pipeline_layout_create_info.pSetLayouts = layouts.ptr();
-		// Needs to be declared in this outer scope, otherwise it may not outlive its assignment
-		// to pipeline_layout_create_info.
-		VkPushConstantRange push_constant_range;
-		if (push_constant.size) {
-			push_constant_range.stageFlags = push_constant.vk_stages_mask;
-			push_constant_range.offset = 0;
-			push_constant_range.size = push_constant.size;
-
-			pipeline_layout_create_info.pushConstantRangeCount = 1;
-			pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
-		} else {
-			pipeline_layout_create_info.pushConstantRangeCount = 0;
-			pipeline_layout_create_info.pPushConstantRanges = nullptr;
-		}
-
-		VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &shader->pipeline_layout);
-
-		if (err) {
-			error_text = "Error (" + itos(err) + ") creating pipeline layout.";
-			success = false;
-		}
-	}
-
-	if (!success) {
-		// Clean up if failed.
-		for (int i = 0; i < shader->pipeline_stages.size(); i++) {
-			vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr);
-		}
-
-		for (int i = 0; i < shader->sets.size(); i++) {
-			vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr);
-		}
-
-		shader_owner.free(id);
-
-		ERR_FAIL_V_MSG(RID(), error_text);
-	}
-
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceVulkan::shader_create_placeholder() {
-	Shader shader;
-	return shader_owner.make_rid(shader);
-}
-
-uint64_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) {
-	_THREAD_SAFE_METHOD_
-
-	const Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, 0);
-	return shader->vertex_input_mask;
-}
-
-/******************/
-/**** UNIFORMS ****/
-/******************/
-
-RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	Buffer buffer;
-	Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
-	ERR_FAIL_COND_V(err != OK, RID());
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-		_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false);
-	}
-	RID id = uniform_buffer_owner.make_rid(buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, BitField<StorageBufferUsage> p_usage) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
-
-	Buffer buffer;
-	uint32_t flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
-	if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {
-		flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
-	}
-	Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&buffer, 0, r, data_size);
-		_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false);
-	}
-	return storage_buffer_owner.make_rid(buffer);
-}
-
-RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) {
-	_THREAD_SAFE_METHOD_
-
-	uint32_t element_size = get_format_vertex_size(p_format);
-	ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers");
-	uint64_t size_bytes = uint64_t(element_size) * p_size_elements;
-
-	ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID());
-
-	TextureBuffer texture_buffer;
-	Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
-	ERR_FAIL_COND_V(err != OK, RID());
-
-	if (p_data.size()) {
-		uint64_t data_size = p_data.size();
-		const uint8_t *r = p_data.ptr();
-		_buffer_update(&texture_buffer.buffer, 0, r, data_size);
-		_buffer_memory_barrier(texture_buffer.buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false);
-	}
-
-	VkBufferViewCreateInfo view_create_info;
-	view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
-	view_create_info.pNext = nullptr;
-	view_create_info.flags = 0;
-	view_create_info.buffer = texture_buffer.buffer.buffer;
-	view_create_info.format = vulkan_formats[p_format];
-	view_create_info.offset = 0;
-	view_create_info.range = size_bytes;
-
-	texture_buffer.view = VK_NULL_HANDLE;
-
-	VkResult res = vkCreateBufferView(device, &view_create_info, nullptr, &texture_buffer.view);
-	if (res) {
-		_buffer_free(&texture_buffer.buffer);
-		ERR_FAIL_V_MSG(RID(), "Unable to create buffer view, error " + itos(res) + ".");
-	}
-
-	// Allocate the view.
-	RID id = texture_buffer_owner.make_rid(texture_buffer);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	return id;
-}
-
-RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) {
-	if (!descriptor_pools.has(p_key)) {
-		descriptor_pools[p_key] = HashSet<DescriptorPool *>();
-	}
-
-	DescriptorPool *pool = nullptr;
-
-	for (DescriptorPool *E : descriptor_pools[p_key]) {
-		if (E->usage < max_descriptors_per_pool) {
-			pool = E;
-			break;
-		}
-	}
-
-	if (!pool) {
-		// Create a new one.
-		pool = memnew(DescriptorPool);
-		pool->usage = 0;
-
-		VkDescriptorPoolCreateInfo descriptor_pool_create_info;
-		descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
-		descriptor_pool_create_info.pNext = nullptr;
-		descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag.
-		descriptor_pool_create_info.maxSets = max_descriptors_per_pool;
-		Vector<VkDescriptorPoolSize> sizes;
-		// Here comes more vulkan API strangeness.
-
-		if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_SAMPLER;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_TEXTURE] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_IMAGE]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] || p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
-			s.descriptorCount = (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] + p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-		if (p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-
-		if (p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-
-		if (p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT]) {
-			VkDescriptorPoolSize s;
-			s.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
-			s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT] * max_descriptors_per_pool;
-			sizes.push_back(s);
-		}
-
-		descriptor_pool_create_info.poolSizeCount = sizes.size();
-		descriptor_pool_create_info.pPoolSizes = sizes.ptr();
-		VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &pool->pool);
-		if (res) {
-			memdelete(pool);
-			ERR_FAIL_COND_V_MSG(res, nullptr, "vkCreateDescriptorPool failed with error " + itos(res) + ".");
-		}
-		descriptor_pools[p_key].insert(pool);
-	}
-
-	pool->usage++;
-
-	return pool;
-}
-
-void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool) {
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND(!descriptor_pools[p_key].has(p_pool));
-#endif
-	ERR_FAIL_COND(p_pool->usage == 0);
-	p_pool->usage--;
-	if (p_pool->usage == 0) {
-		vkDestroyDescriptorPool(device, p_pool->pool, nullptr);
-		descriptor_pools[p_key].erase(p_pool);
-		memdelete(p_pool);
-		if (descriptor_pools[p_key].is_empty()) {
-			descriptor_pools.erase(p_key);
-		}
-	}
-}
-
-RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V(p_uniforms.size() == 0, RID());
-
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(),
-			"Desired set (" + itos(p_shader_set) + ") not used by shader.");
-	// See that all sets in shader are satisfied.
-
-	const Shader::Set &set = shader->sets[p_shader_set];
-
-	uint32_t uniform_count = p_uniforms.size();
-	const Uniform *uniforms = p_uniforms.ptr();
-
-	uint32_t set_uniform_count = set.uniform_info.size();
-	const UniformInfo *set_uniforms = set.uniform_info.ptr();
-
-	Vector<VkWriteDescriptorSet> writes;
-	DescriptorPoolKey pool_key;
-
-	// To keep them alive until update call.
-	List<Vector<VkDescriptorBufferInfo>> buffer_infos;
-	List<Vector<VkBufferView>> buffer_views;
-	List<Vector<VkDescriptorImageInfo>> image_infos;
-	// Used for verification to make sure a uniform set does not use a framebuffer bound texture.
-	LocalVector<UniformSet::AttachableTexture> attachable_textures;
-	Vector<Texture *> mutable_sampled_textures;
-	Vector<Texture *> mutable_storage_textures;
-
-	for (uint32_t i = 0; i < set_uniform_count; i++) {
-		const UniformInfo &set_uniform = set_uniforms[i];
-		int uniform_idx = -1;
-		for (int j = 0; j < (int)uniform_count; j++) {
-			if (uniforms[j].binding == set_uniform.binding) {
-				uniform_idx = j;
-			}
-		}
-		ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(),
-				"All the shader bindings for the given set must be covered by the uniforms provided. Binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + ") was not provided.");
-
-		const Uniform &uniform = uniforms[uniform_idx];
-
-		ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(),
-				"Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'.");
-
-		VkWriteDescriptorSet write; // Common header.
-		write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
-		write.pNext = nullptr;
-		write.dstSet = VK_NULL_HANDLE; // Will assign afterwards when everything is valid.
-		write.dstBinding = set_uniform.binding;
-		write.dstArrayElement = 0;
-		write.descriptorCount = 0;
-		write.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; // Invalid value.
-		write.pImageInfo = nullptr;
-		write.pBufferInfo = nullptr;
-		write.pTexelBufferView = nullptr;
-		uint32_t type_size = 1;
-
-		switch (uniform.uniform_type) {
-			case UNIFORM_TYPE_SAMPLER: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_NULL_V_MSG(sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = *sampler;
-					img_info.imageView = VK_NULL_HANDLE;
-					img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-
-					image_info.push_back(img_info);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count();
-				write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = nullptr;
-				write.pTexelBufferView = nullptr;
-
-				type_size = uniform.get_id_count();
-
-			} break;
-			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
-					VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
-					ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
-
-					Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1));
-					ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = *sampler;
-					img_info.imageView = texture->view;
-
-					if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
-						UniformSet::AttachableTexture attachable_texture;
-						attachable_texture.bind = set_uniform.binding;
-						attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1);
-						attachable_textures.push_back(attachable_texture);
-					}
-
-					if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
-						// Can also be used as storage, add to mutable sampled.
-						mutable_sampled_textures.push_back(texture);
-					}
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-
-					img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-					image_info.push_back(img_info);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count() / 2;
-				write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = nullptr;
-				write.pTexelBufferView = nullptr;
-
-				type_size = uniform.get_id_count() / 2;
-
-			} break;
-			case UNIFORM_TYPE_TEXTURE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = VK_NULL_HANDLE;
-					img_info.imageView = texture->view;
-
-					if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
-						UniformSet::AttachableTexture attachable_texture;
-						attachable_texture.bind = set_uniform.binding;
-						attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j);
-						attachable_textures.push_back(attachable_texture);
-					}
-
-					if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
-						// Can also be used as storage, add to mutable sampled.
-						mutable_sampled_textures.push_back(texture);
-					}
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-
-					img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-					image_info.push_back(img_info);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count();
-				write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = nullptr;
-				write.pTexelBufferView = nullptr;
-
-				type_size = uniform.get_id_count();
-			} break;
-			case UNIFORM_TYPE_IMAGE: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
-
-					ERR_FAIL_NULL_V_MSG(texture, RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
-							"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = VK_NULL_HANDLE;
-					img_info.imageView = texture->view;
-
-					if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
-						// Can also be used as storage, add to mutable sampled.
-						mutable_storage_textures.push_back(texture);
-					}
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-
-					img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
-					image_info.push_back(img_info);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count();
-				write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = nullptr;
-				write.pTexelBufferView = nullptr;
-
-				type_size = uniform.get_id_count();
-
-			} break;
-			case UNIFORM_TYPE_TEXTURE_BUFFER: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorBufferInfo> buffer_info;
-				Vector<VkBufferView> buffer_view;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j));
-					ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
-
-					buffer_info.push_back(buffer->buffer.buffer_info);
-					buffer_view.push_back(buffer->view);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count();
-				write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
-				write.pImageInfo = nullptr;
-				write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr();
-				write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr();
-
-				type_size = uniform.get_id_count();
-
-			} break;
-			case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-				Vector<VkDescriptorBufferInfo> buffer_info;
-				Vector<VkBufferView> buffer_view;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
-					VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
-					ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
-
-					TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = *sampler;
-					img_info.imageView = VK_NULL_HANDLE;
-					img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-
-					image_info.push_back(img_info);
-
-					ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
-
-					buffer_info.push_back(buffer->buffer.buffer_info);
-					buffer_view.push_back(buffer->view);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count() / 2;
-				write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr();
-				write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr();
-
-				type_size = uniform.get_id_count() / 2;
-			} break;
-			case UNIFORM_TYPE_IMAGE_BUFFER: {
-				// Todo.
-
-			} break;
-			case UNIFORM_TYPE_UNIFORM_BUFFER: {
-				ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
-						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
-
-				Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0));
-				ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
-
-				ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(),
-						"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = 1;
-				write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-				write.pImageInfo = nullptr;
-				write.pBufferInfo = &buffer->buffer_info;
-				write.pTexelBufferView = nullptr;
-
-			} break;
-			case UNIFORM_TYPE_STORAGE_BUFFER: {
-				ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
-						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
-
-				Buffer *buffer = nullptr;
-
-				if (storage_buffer_owner.owns(uniform.get_id(0))) {
-					buffer = storage_buffer_owner.get_or_null(uniform.get_id(0));
-				} else if (vertex_buffer_owner.owns(uniform.get_id(0))) {
-					buffer = vertex_buffer_owner.get_or_null(uniform.get_id(0));
-
-					ERR_FAIL_COND_V_MSG(!(buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");
-				}
-				ERR_FAIL_NULL_V_MSG(buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
-
-				// If 0, then it's sized on link time.
-				ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
-						"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = 1;
-				write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
-				write.pImageInfo = nullptr;
-				write.pBufferInfo = &buffer->buffer_info;
-				write.pTexelBufferView = nullptr;
-			} break;
-			case UNIFORM_TYPE_INPUT_ATTACHMENT: {
-				ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");
-
-				if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
-					if (set_uniform.length > 1) {
-						ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					} else {
-						ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
-					}
-				}
-
-				Vector<VkDescriptorImageInfo> image_info;
-
-				for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
-					Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
-
-					ERR_FAIL_NULL_V_MSG(texture, RID(),
-							"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
-
-					ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
-							"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
-
-					VkDescriptorImageInfo img_info;
-					img_info.sampler = VK_NULL_HANDLE;
-					img_info.imageView = texture->view;
-
-					DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
-
-					img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-					image_info.push_back(img_info);
-				}
-
-				write.dstArrayElement = 0;
-				write.descriptorCount = uniform.get_id_count();
-				write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
-				write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
-				write.pBufferInfo = nullptr;
-				write.pTexelBufferView = nullptr;
-
-				type_size = uniform.get_id_count();
-			} break;
-			default: {
-			}
-		}
-
-		writes.push_back(write);
-
-		ERR_FAIL_COND_V_MSG(pool_key.uniform_type[set_uniform.type] == MAX_DESCRIPTOR_POOL_ELEMENT, RID(),
-				"Uniform set reached the limit of bindings for the same type (" + itos(MAX_DESCRIPTOR_POOL_ELEMENT) + ").");
-		pool_key.uniform_type[set_uniform.type] += type_size;
-	}
-
-	// Need a descriptor pool.
-	DescriptorPool *pool = _descriptor_pool_allocate(pool_key);
-
-	ERR_FAIL_NULL_V(pool, RID());
-
-	VkDescriptorSetAllocateInfo descriptor_set_allocate_info;
-
-	descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
-	descriptor_set_allocate_info.pNext = nullptr;
-	descriptor_set_allocate_info.descriptorPool = pool->pool;
-	descriptor_set_allocate_info.descriptorSetCount = 1;
-	descriptor_set_allocate_info.pSetLayouts = &shader->sets[p_shader_set].descriptor_set_layout;
-
-	VkDescriptorSet descriptor_set;
-
-	VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set);
-	if (res) {
-		_descriptor_pool_free(pool_key, pool); // Meh.
-		ERR_FAIL_V_MSG(RID(), "Cannot allocate descriptor sets, error " + itos(res) + ".");
-	}
-
-	UniformSet uniform_set;
-	uniform_set.pool = pool;
-	uniform_set.pool_key = pool_key;
-	uniform_set.descriptor_set = descriptor_set;
-	uniform_set.format = shader->set_formats[p_shader_set];
-	uniform_set.attachable_textures = attachable_textures;
-	uniform_set.mutable_sampled_textures = mutable_sampled_textures;
-	uniform_set.mutable_storage_textures = mutable_storage_textures;
-	uniform_set.shader_set = p_shader_set;
-	uniform_set.shader_id = p_shader;
-
-	RID id = uniform_set_owner.make_rid(uniform_set);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	// Add dependencies.
-	_add_dependency(id, p_shader);
-	for (uint32_t i = 0; i < uniform_count; i++) {
-		const Uniform &uniform = uniforms[i];
-		int id_count = uniform.get_id_count();
-		for (int j = 0; j < id_count; j++) {
-			_add_dependency(id, uniform.get_id(j));
-		}
-	}
-
-	// Write the contents.
-	if (writes.size()) {
-		for (int i = 0; i < writes.size(); i++) {
-			writes.write[i].dstSet = descriptor_set;
-		}
-		vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, nullptr);
-	}
-
-	return id;
-}
-
-bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
-	return uniform_set_owner.owns(p_uniform_set);
-}
-
-void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {
-	UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(us);
-	us->invalidated_callback = p_callback;
-	us->invalidated_callback_userdata = p_userdata;
-}
-
-Error RenderingDeviceVulkan::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Copying buffers is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Copying buffers is forbidden during creation of a compute list");
-
-	// This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed
-	// for the source or destination buffers before performing the copy. These masks are effectively ignored.
-	VkPipelineStageFlags src_stage_mask = 0;
-	VkAccessFlags src_access_mask = 0;
-	Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_NO_BARRIER);
-	if (!src_buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type.");
-	}
-
-	VkPipelineStageFlags dst_stage_mask = 0;
-	VkAccessFlags dst_access = 0;
-	if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-		// If the post barrier mask defines it, we indicate the destination buffer will require a barrier with these flags set
-		// after the copy command is queued.
-		dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
-		dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stage_mask, dst_access, p_post_barrier);
-	if (!dst_buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type.");
-	}
-
-	// Validate the copy's dimensions for both buffers.
-	ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer.");
-	ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer.");
-
-	// Perform the copy.
-	VkBufferCopy region;
-	region.srcOffset = p_src_offset;
-	region.dstOffset = p_dst_offset;
-	region.size = p_size;
-	vkCmdCopyBuffer(frames[frame].draw_command_buffer, src_buffer->buffer, dst_buffer->buffer, 1, &region);
-
-#ifdef FORCE_FULL_BARRIER
-	_full_barrier(true);
-#else
-	if (dst_stage_mask == 0) {
-		dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-	}
-
-	// As indicated by the post barrier mask, push a new barrier.
-	if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
-		_buffer_memory_barrier(dst_buffer->buffer, p_dst_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
-	}
-#endif
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a compute list");
-
-	VkPipelineStageFlags dst_stage_mask = 0;
-	VkAccessFlags dst_access = 0;
-	if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-		// Protect subsequent updates.
-		dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
-		dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-	Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stage_mask, dst_access, p_post_barrier);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
-	}
-
-	ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
-			"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
-
-	// No barrier should be needed here.
-	// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true);
-
-	Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, true);
-	if (err) {
-		return err;
-	}
-
-#ifdef FORCE_FULL_BARRIER
-	_full_barrier(true);
-#else
-	if (dst_stage_mask == 0) {
-		dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-	}
-
-	if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
-		_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
-	}
-
-#endif
-	return err;
-}
-
-Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
-			"Size must be a multiple of four");
-	ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
-			"Updating buffers in is forbidden during creation of a draw list");
-	ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
-			"Updating buffers is forbidden during creation of a compute list");
-
-	VkPipelineStageFlags dst_stage_mask = 0;
-	VkAccessFlags dst_access = 0;
-	if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-		// Protect subsequent updates.
-		dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
-		dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stage_mask, dst_access, p_post_barrier);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
-	}
-
-	ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
-			"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
-
-	vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0);
-
-#ifdef FORCE_FULL_BARRIER
-	_full_barrier(true);
-#else
-	if (dst_stage_mask == 0) {
-		dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-	}
-
-	_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
-
-#endif
-	return OK;
-}
-
-Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) {
-	_THREAD_SAFE_METHOD_
-
-	// It could be this buffer was just created.
-	VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
-	VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
-	// Get the vulkan buffer and the potential stage/access possible.
-	Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL_BARRIERS);
-	if (!buffer) {
-		ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
-	}
-
-	// Make sure no one is using the buffer -- the "true" gets us to the same command buffer as below.
-	_buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, src_access_mask, VK_ACCESS_TRANSFER_READ_BIT, true);
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-
-	// Size of buffer to retrieve.
-	if (!p_size) {
-		p_size = buffer->size;
-	} else {
-		ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(),
-				"Size is larger than the buffer.");
-	}
-
-	Buffer tmp_buffer;
-	_buffer_allocate(&tmp_buffer, p_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
-	VkBufferCopy region;
-	region.srcOffset = p_offset;
-	region.dstOffset = 0;
-	region.size = p_size;
-	vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, &region); // Dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.
-	// Flush everything so memory can be safely mapped.
-	_flush(true);
-
-	void *buffer_mem;
-	VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem);
-	ERR_FAIL_COND_V_MSG(vkerr, Vector<uint8_t>(), "vmaMapMemory failed with error " + itos(vkerr) + ".");
-
-	Vector<uint8_t> buffer_data;
-	{
-		buffer_data.resize(p_size);
-		uint8_t *w = buffer_data.ptrw();
-		memcpy(w, buffer_mem, p_size);
-	}
-
-	vmaUnmapMemory(allocator, tmp_buffer.allocation);
-
-	_buffer_free(&tmp_buffer);
-
-	return buffer_data;
-}
-
-/*************************/
-/**** RENDER PIPELINE ****/
-/*************************/
-
-RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-	_THREAD_SAFE_METHOD_
-
-	// Needs a shader.
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(shader->is_compute, RID(),
-			"Compute shaders can't be used in render pipelines");
-
-	if (p_framebuffer_format == INVALID_ID) {
-		// If nothing provided, use an empty one (no attachments).
-		p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());
-	}
-	ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());
-	const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format];
-
-	{ // Validate shader vs framebuffer.
-
-		ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds");
-		const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
-		uint32_t output_mask = 0;
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) {
-				output_mask |= 1 << i;
-			}
-		}
-		ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),
-				"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");
-	}
-	// Vertex.
-	VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info;
-
-	if (p_vertex_format != INVALID_ID) {
-		// Uses vertices, else it does not.
-		ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
-		const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
-
-		pipeline_vertex_input_state_create_info = vd.create_info;
-
-		// Validate with inputs.
-		for (uint64_t i = 0; i < 64; i++) {
-			if (!(shader->vertex_input_mask & (1ULL << i))) {
-				continue;
-			}
-			bool found = false;
-			for (int j = 0; j < vd.vertex_formats.size(); j++) {
-				if (vd.vertex_formats[j].location == i) {
-					found = true;
-				}
-			}
-
-			ERR_FAIL_COND_V_MSG(!found, RID(),
-					"Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation.");
-		}
-
-	} else {
-		// Does not use vertices.
-		pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-		pipeline_vertex_input_state_create_info.pNext = nullptr;
-		pipeline_vertex_input_state_create_info.flags = 0;
-		pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = 0;
-		pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = nullptr;
-		pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0;
-		pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = nullptr;
-
-		ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),
-				"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");
-	}
-	// Input assembly.
-
-	ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());
-
-	VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info;
-	input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
-	input_assembly_create_info.pNext = nullptr;
-	input_assembly_create_info.flags = 0;
-
-	static const VkPrimitiveTopology topology_list[RENDER_PRIMITIVE_MAX] = {
-		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
-		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
-		VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
-		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
-		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
-		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
-		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
-		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
-		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
-		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
-		VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
-	};
-
-	input_assembly_create_info.topology = topology_list[p_render_primitive];
-	input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX);
-
-	// Tessellation.
-	VkPipelineTessellationStateCreateInfo tessellation_create_info;
-	tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
-	tessellation_create_info.pNext = nullptr;
-	tessellation_create_info.flags = 0;
-	ERR_FAIL_COND_V(limits.maxTessellationPatchSize > 0 && (p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize), RID());
-	tessellation_create_info.patchControlPoints = p_rasterization_state.patch_control_points;
-
-	VkPipelineViewportStateCreateInfo viewport_state_create_info;
-	viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
-	viewport_state_create_info.pNext = nullptr;
-	viewport_state_create_info.flags = 0;
-	viewport_state_create_info.viewportCount = 1; // If VR extensions are supported at some point, this will have to be customizable in the framebuffer format.
-	viewport_state_create_info.pViewports = nullptr;
-	viewport_state_create_info.scissorCount = 1;
-	viewport_state_create_info.pScissors = nullptr;
-
-	// Rasterization.
-	VkPipelineRasterizationStateCreateInfo rasterization_state_create_info;
-	rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
-	rasterization_state_create_info.pNext = nullptr;
-	rasterization_state_create_info.flags = 0;
-	rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp;
-	rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives;
-	rasterization_state_create_info.polygonMode = (p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL);
-	static const VkCullModeFlags cull_mode[3] = {
-		VK_CULL_MODE_NONE,
-		VK_CULL_MODE_FRONT_BIT,
-		VK_CULL_MODE_BACK_BIT
-	};
-
-	ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());
-	rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode];
-	rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE);
-	rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enabled;
-	rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor;
-	rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp;
-	rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
-	rasterization_state_create_info.lineWidth = p_rasterization_state.line_width;
-
-	// Multisample.
-	VkPipelineMultisampleStateCreateInfo multisample_state_create_info;
-	multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
-	multisample_state_create_info.pNext = nullptr;
-	multisample_state_create_info.flags = 0;
-
-	multisample_state_create_info.rasterizationSamples = _ensure_supported_sample_count(p_multisample_state.sample_count);
-	multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading;
-	multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading;
-	Vector<VkSampleMask> sample_mask;
-	if (p_multisample_state.sample_mask.size()) {
-		// Use sample mask.
-		const int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = {
-			1, 2, 4, 8, 16, 32, 64
-		};
-		ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID());
-		sample_mask.resize(p_multisample_state.sample_mask.size());
-		for (int i = 0; i < p_multisample_state.sample_mask.size(); i++) {
-			VkSampleMask mask = p_multisample_state.sample_mask[i];
-			sample_mask.push_back(mask);
-		}
-		multisample_state_create_info.pSampleMask = sample_mask.ptr();
-	} else {
-		multisample_state_create_info.pSampleMask = nullptr;
-	}
-
-	multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
-	multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one;
-
-	// Depth stencil.
-
-	VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info;
-	depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
-	depth_stencil_state_create_info.pNext = nullptr;
-	depth_stencil_state_create_info.flags = 0;
-	depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test;
-	depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write;
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID());
-	depth_stencil_state_create_info.depthCompareOp = compare_operators[p_depth_stencil_state.depth_compare_operator];
-	depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;
-	depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil;
-
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.front.failOp = stencil_operations[p_depth_stencil_state.front_op.fail];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.front.passOp = stencil_operations[p_depth_stencil_state.front_op.pass];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.front.depthFailOp = stencil_operations[p_depth_stencil_state.front_op.depth_fail];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID());
-	depth_stencil_state_create_info.front.compareOp = compare_operators[p_depth_stencil_state.front_op.compare];
-	depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.front_op.compare_mask;
-	depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.front_op.write_mask;
-	depth_stencil_state_create_info.front.reference = p_depth_stencil_state.front_op.reference;
-
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.back.failOp = stencil_operations[p_depth_stencil_state.back_op.fail];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.back.passOp = stencil_operations[p_depth_stencil_state.back_op.pass];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID());
-	depth_stencil_state_create_info.back.depthFailOp = stencil_operations[p_depth_stencil_state.back_op.depth_fail];
-	ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID());
-	depth_stencil_state_create_info.back.compareOp = compare_operators[p_depth_stencil_state.back_op.compare];
-	depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.back_op.compare_mask;
-	depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.back_op.write_mask;
-	depth_stencil_state_create_info.back.reference = p_depth_stencil_state.back_op.reference;
-
-	depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min;
-	depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max;
-
-	// Blend state.
-	VkPipelineColorBlendStateCreateInfo color_blend_state_create_info;
-	color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
-	color_blend_state_create_info.pNext = nullptr;
-	color_blend_state_create_info.flags = 0;
-	color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op;
-	ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID());
-	color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op];
-
-	Vector<VkPipelineColorBlendAttachmentState> attachment_states;
-	{
-		const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
-		attachment_states.resize(pass.color_attachments.size());
-		ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());
-		for (int i = 0; i < pass.color_attachments.size(); i++) {
-			VkPipelineColorBlendAttachmentState state;
-			if (pass.color_attachments[i] == FramebufferPass::ATTACHMENT_UNUSED) {
-				state.blendEnable = false;
-
-				state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
-				state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
-				state.colorBlendOp = VK_BLEND_OP_ADD;
-
-				state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
-				state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
-				state.alphaBlendOp = VK_BLEND_OP_ADD;
-
-				state.colorWriteMask = 0;
-			} else {
-				state.blendEnable = p_blend_state.attachments[i].enable_blend;
-
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
-				state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor];
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
-				state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor];
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());
-				state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op];
-
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
-				state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor];
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
-				state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor];
-				ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());
-				state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op];
-
-				state.colorWriteMask = 0;
-				if (p_blend_state.attachments[i].write_r) {
-					state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
-				}
-				if (p_blend_state.attachments[i].write_g) {
-					state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
-				}
-				if (p_blend_state.attachments[i].write_b) {
-					state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
-				}
-				if (p_blend_state.attachments[i].write_a) {
-					state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
-				}
-			}
-			attachment_states.write[i] = state;
-		}
-	}
-
-	color_blend_state_create_info.attachmentCount = attachment_states.size();
-	color_blend_state_create_info.pAttachments = attachment_states.ptr();
-
-	color_blend_state_create_info.blendConstants[0] = p_blend_state.blend_constant.r;
-	color_blend_state_create_info.blendConstants[1] = p_blend_state.blend_constant.g;
-	color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b;
-	color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a;
-
-	// Dynamic state.
-
-	VkPipelineDynamicStateCreateInfo dynamic_state_create_info;
-	dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
-	dynamic_state_create_info.pNext = nullptr;
-	dynamic_state_create_info.flags = 0;
-	Vector<VkDynamicState> dynamic_states; // Vulkan is weird.
-
-	dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); // Viewport and scissor are always dynamic.
-	dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_LINE_WIDTH)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BIAS)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_BLEND_CONSTANTS)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BOUNDS)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_COMPARE_MASK)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_WRITE_MASK)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
-	}
-
-	if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_REFERENCE)) {
-		dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
-	}
-
-	dynamic_state_create_info.dynamicStateCount = dynamic_states.size();
-	dynamic_state_create_info.pDynamicStates = dynamic_states.ptr();
-
-	void *graphics_pipeline_nextptr = nullptr;
-
-	VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info;
-	if (context->get_vrs_capabilities().attachment_vrs_supported) {
-		// If VRS is used, this defines how the different VRS types are combined.
-		// combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS.
-		// combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS.
-
-		vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR;
-		vrs_create_info.pNext = nullptr;
-		vrs_create_info.fragmentSize = { 4, 4 };
-		vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter.
-		vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // Always use the outcome of attachment VRS if enabled.
-
-		graphics_pipeline_nextptr = &vrs_create_info;
-	}
-
-	// Finally, pipeline create info.
-	VkGraphicsPipelineCreateInfo graphics_pipeline_create_info;
-
-	graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
-	graphics_pipeline_create_info.pNext = graphics_pipeline_nextptr;
-	graphics_pipeline_create_info.flags = 0;
-
-	Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages;
-	Vector<VkSpecializationInfo> specialization_info;
-	Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries;
-	Vector<uint32_t> specialization_constant_data;
-
-	if (shader->specialization_constants.size()) {
-		specialization_constant_data.resize(shader->specialization_constants.size());
-		uint32_t *data_ptr = specialization_constant_data.ptrw();
-		specialization_info.resize(pipeline_stages.size());
-		specialization_map_entries.resize(pipeline_stages.size());
-		for (int i = 0; i < shader->specialization_constants.size(); i++) {
-			// See if overridden.
-			const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
-			data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
-
-			for (int j = 0; j < p_specialization_constants.size(); j++) {
-				const PipelineSpecializationConstant &psc = p_specialization_constants[j];
-				if (psc.constant_id == sc.constant.constant_id) {
-					ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
-					data_ptr[i] = psc.int_value;
-					break;
-				}
-			}
-
-			VkSpecializationMapEntry entry;
-
-			entry.constantID = sc.constant.constant_id;
-			entry.offset = i * sizeof(uint32_t);
-			entry.size = sizeof(uint32_t);
-
-			for (int j = 0; j < SHADER_STAGE_MAX; j++) {
-				if (sc.stage_flags & (1 << j)) {
-					VkShaderStageFlagBits stage = shader_stage_masks[j];
-					for (int k = 0; k < pipeline_stages.size(); k++) {
-						if (pipeline_stages[k].stage == stage) {
-							specialization_map_entries.write[k].push_back(entry);
-						}
-					}
-				}
-			}
-		}
-
-		for (int i = 0; i < pipeline_stages.size(); i++) {
-			if (specialization_map_entries[i].size()) {
-				specialization_info.write[i].dataSize = specialization_constant_data.size() * sizeof(uint32_t);
-				specialization_info.write[i].pData = data_ptr;
-				specialization_info.write[i].mapEntryCount = specialization_map_entries[i].size();
-				specialization_info.write[i].pMapEntries = specialization_map_entries[i].ptr();
-				pipeline_stages.write[i].pSpecializationInfo = specialization_info.ptr() + i;
-			}
-		}
-	}
-
-	graphics_pipeline_create_info.stageCount = pipeline_stages.size();
-	graphics_pipeline_create_info.pStages = pipeline_stages.ptr();
-
-	graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info;
-	graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info;
-	graphics_pipeline_create_info.pTessellationState = &tessellation_create_info;
-	graphics_pipeline_create_info.pViewportState = &viewport_state_create_info;
-	graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info;
-	graphics_pipeline_create_info.pMultisampleState = &multisample_state_create_info;
-	graphics_pipeline_create_info.pDepthStencilState = &depth_stencil_state_create_info;
-	graphics_pipeline_create_info.pColorBlendState = &color_blend_state_create_info;
-	graphics_pipeline_create_info.pDynamicState = &dynamic_state_create_info;
-	graphics_pipeline_create_info.layout = shader->pipeline_layout;
-	graphics_pipeline_create_info.renderPass = fb_format.render_pass;
-
-	graphics_pipeline_create_info.subpass = p_for_render_pass;
-	graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
-	graphics_pipeline_create_info.basePipelineIndex = 0;
-
-	RenderPipeline pipeline;
-	VkResult err = vkCreateGraphicsPipelines(device, pipelines_cache.cache_object, 1, &graphics_pipeline_create_info, nullptr, &pipeline.pipeline);
-	ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + " for shader '" + shader->name + "'.");
-
-	if (pipelines_cache.cache_object != VK_NULL_HANDLE) {
-		_update_pipeline_cache();
-	}
-
-	pipeline.set_formats = shader->set_formats;
-	pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
-	pipeline.pipeline_layout = shader->pipeline_layout;
-	pipeline.shader = p_shader;
-	pipeline.push_constant_size = shader->push_constant.size;
-
-#ifdef DEBUG_ENABLED
-	pipeline.validation.dynamic_state = p_dynamic_state_flags;
-	pipeline.validation.framebuffer_format = p_framebuffer_format;
-	pipeline.validation.render_pass = p_for_render_pass;
-	pipeline.validation.vertex_format = p_vertex_format;
-	pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable;
-
-	static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = {
-		1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1
-	};
-	pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive];
-	static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = {
-		1,
-		2,
-		2,
-		2,
-		2,
-		3,
-		3,
-		3,
-		3,
-		3,
-		1,
-	};
-	pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];
-#endif
-	// Create ID to associate with this pipeline.
-	RID id = render_pipeline_owner.make_rid(pipeline);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	// Now add all the dependencies.
-	_add_dependency(id, p_shader);
-	return id;
-}
-
-bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) {
-	_THREAD_SAFE_METHOD_
-	return render_pipeline_owner.owns(p_pipeline);
-}
-
-/**************************/
-/**** COMPUTE PIPELINE ****/
-/**************************/
-
-RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
-	_THREAD_SAFE_METHOD_
-
-	// Needs a shader.
-	Shader *shader = shader_owner.get_or_null(p_shader);
-	ERR_FAIL_NULL_V(shader, RID());
-
-	ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
-			"Non-compute shaders can't be used in compute pipelines");
-
-	// Finally, pipeline create info.
-	VkComputePipelineCreateInfo compute_pipeline_create_info;
-
-	compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
-	compute_pipeline_create_info.pNext = nullptr;
-	compute_pipeline_create_info.flags = 0;
-
-	compute_pipeline_create_info.stage = shader->pipeline_stages[0];
-	compute_pipeline_create_info.layout = shader->pipeline_layout;
-	compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
-	compute_pipeline_create_info.basePipelineIndex = 0;
-
-	VkSpecializationInfo specialization_info;
-	Vector<VkSpecializationMapEntry> specialization_map_entries;
-	Vector<uint32_t> specialization_constant_data;
-
-	if (shader->specialization_constants.size()) {
-		specialization_constant_data.resize(shader->specialization_constants.size());
-		uint32_t *data_ptr = specialization_constant_data.ptrw();
-		for (int i = 0; i < shader->specialization_constants.size(); i++) {
-			// See if overridden.
-			const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
-			data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
-
-			for (int j = 0; j < p_specialization_constants.size(); j++) {
-				const PipelineSpecializationConstant &psc = p_specialization_constants[j];
-				if (psc.constant_id == sc.constant.constant_id) {
-					ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
-					data_ptr[i] = psc.int_value;
-					break;
-				}
-			}
-
-			VkSpecializationMapEntry entry;
-
-			entry.constantID = sc.constant.constant_id;
-			entry.offset = i * sizeof(uint32_t);
-			entry.size = sizeof(uint32_t);
-
-			specialization_map_entries.push_back(entry);
-		}
-
-		specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t);
-		specialization_info.pData = data_ptr;
-		specialization_info.mapEntryCount = specialization_map_entries.size();
-		specialization_info.pMapEntries = specialization_map_entries.ptr();
-
-		compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info;
-	}
-
-	ComputePipeline pipeline;
-	VkResult err = vkCreateComputePipelines(device, pipelines_cache.cache_object, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline);
-	ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
-
-	if (pipelines_cache.cache_object != VK_NULL_HANDLE) {
-		_update_pipeline_cache();
-	}
-
-	pipeline.set_formats = shader->set_formats;
-	pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
-	pipeline.pipeline_layout = shader->pipeline_layout;
-	pipeline.shader = p_shader;
-	pipeline.push_constant_size = shader->push_constant.size;
-	pipeline.local_group_size[0] = shader->compute_local_size[0];
-	pipeline.local_group_size[1] = shader->compute_local_size[1];
-	pipeline.local_group_size[2] = shader->compute_local_size[2];
-
-	// Create ID to associate with this pipeline.
-	RID id = compute_pipeline_owner.make_rid(pipeline);
-#ifdef DEV_ENABLED
-	set_resource_name(id, "RID:" + itos(id.get_id()));
-#endif
-	// Now add all the dependencies.
-	_add_dependency(id, p_shader);
-	return id;
-}
-
-bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) {
-	return compute_pipeline_owner.owns(p_pipeline);
-}
-
-/****************/
-/**** SCREEN ****/
-/****************/
-
-int RenderingDeviceVulkan::screen_get_width(DisplayServer::WindowID p_screen) const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen");
-	return context->window_get_width(p_screen);
-}
-
-int RenderingDeviceVulkan::screen_get_height(DisplayServer::WindowID p_screen) const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen");
-
-	return context->window_get_height(p_screen);
-}
-
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
-
-	// Very hacky, but not used often per frame so I guess ok.
-	VkFormat vkformat = context->get_screen_format();
-	DataFormat format = DATA_FORMAT_MAX;
-	for (int i = 0; i < DATA_FORMAT_MAX; i++) {
-		if (vkformat == vulkan_formats[i]) {
-			format = DataFormat(i);
-			break;
-		}
-	}
-
-	ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID);
-
-	AttachmentFormat attachment;
-	attachment.format = format;
-	attachment.samples = TEXTURE_SAMPLES_1;
-	attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-	Vector<AttachmentFormat> screen_attachment;
-	screen_attachment.push_back(attachment);
-	return const_cast<RenderingDeviceVulkan *>(this)->framebuffer_format_create(screen_attachment);
-}
-
-/*******************/
-/**** DRAW LIST ****/
-/*******************/
-
-RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-
-	if (!context->window_is_valid_swapchain(p_screen)) {
-		return INVALID_ID;
-	}
-
-	Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen));
-
-	_draw_list_allocate(Rect2i(Vector2i(), size), 0, 0);
-#ifdef DEBUG_ENABLED
-	draw_list_framebuffer_format = screen_get_framebuffer_format();
-#endif
-	draw_list_subpass_count = 1;
-
-	VkRenderPassBeginInfo render_pass_begin;
-	render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-	render_pass_begin.pNext = nullptr;
-	render_pass_begin.renderPass = context->window_get_render_pass(p_screen);
-	render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen);
-
-	render_pass_begin.renderArea.extent.width = size.width;
-	render_pass_begin.renderArea.extent.height = size.height;
-	render_pass_begin.renderArea.offset.x = 0;
-	render_pass_begin.renderArea.offset.y = 0;
-
-	render_pass_begin.clearValueCount = 1;
-
-	VkClearValue clear_value;
-	clear_value.color.float32[0] = p_clear_color.r;
-	clear_value.color.float32[1] = p_clear_color.g;
-	clear_value.color.float32[2] = p_clear_color.b;
-	clear_value.color.float32[3] = p_clear_color.a;
-
-	render_pass_begin.pClearValues = &clear_value;
-
-	vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
-
-	uint32_t size_x = screen_get_width(p_screen);
-	uint32_t size_y = screen_get_height(p_screen);
-
-	VkViewport viewport;
-	viewport.x = 0;
-	viewport.y = 0;
-	viewport.width = size_x;
-	viewport.height = size_y;
-	viewport.minDepth = 0;
-	viewport.maxDepth = 1.0;
-
-	vkCmdSetViewport(command_buffer, 0, 1, &viewport);
-
-	VkRect2D scissor;
-	scissor.offset.x = 0;
-	scissor.offset.y = 0;
-	scissor.extent.width = size_x;
-	scissor.extent.height = size_y;
-
-	vkCmdSetScissor(command_buffer, 0, 1, &scissor);
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-
-Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count) {
-	Framebuffer::VersionKey vk;
-	vk.initial_color_action = p_initial_color_action;
-	vk.final_color_action = p_final_color_action;
-	vk.initial_depth_action = p_initial_depth_action;
-	vk.final_depth_action = p_final_depth_action;
-	vk.view_count = p_framebuffer->view_count;
-
-	if (!p_framebuffer->framebuffers.has(vk)) {
-		// Need to create this version.
-		Framebuffer::Version version;
-
-		version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, framebuffer_formats[p_framebuffer->format_id].E->key().passes, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_framebuffer->view_count);
-
-		VkFramebufferCreateInfo framebuffer_create_info;
-		framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
-		framebuffer_create_info.pNext = nullptr;
-		framebuffer_create_info.flags = 0;
-		framebuffer_create_info.renderPass = version.render_pass;
-		Vector<VkImageView> attachments;
-		for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
-			Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
-			if (texture) {
-				attachments.push_back(texture->view);
-				if (!(texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) { // VRS attachment will be a different size.
-					ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG);
-					ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG);
-				}
-			}
-		}
-		framebuffer_create_info.attachmentCount = attachments.size();
-		framebuffer_create_info.pAttachments = attachments.ptr();
-		framebuffer_create_info.width = p_framebuffer->size.width;
-		framebuffer_create_info.height = p_framebuffer->size.height;
-		framebuffer_create_info.layers = 1;
-
-		VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, &version.framebuffer);
-		ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkCreateFramebuffer failed with error " + itos(err) + ".");
-
-		version.subpass_count = framebuffer_formats[p_framebuffer->format_id].E->key().passes.size();
-
-		p_framebuffer->framebuffers.insert(vk, version);
-	}
-	const Framebuffer::Version &version = p_framebuffer->framebuffers[vk];
-	*r_framebuffer = version.framebuffer;
-	*r_render_pass = version.render_pass;
-	*r_subpass_count = version.subpass_count;
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures, bool p_constrained_to_region) {
-	VkRenderPassBeginInfo render_pass_begin;
-	render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-	render_pass_begin.pNext = nullptr;
-	render_pass_begin.renderPass = render_pass;
-	render_pass_begin.framebuffer = vkframebuffer;
-
-	if (p_constrained_to_region) {
-		render_pass_begin.renderArea.extent.width = viewport_size.width;
-		render_pass_begin.renderArea.extent.height = viewport_size.height;
-		render_pass_begin.renderArea.offset.x = viewport_offset.x;
-		render_pass_begin.renderArea.offset.y = viewport_offset.y;
-	} else {
-		render_pass_begin.renderArea.extent.width = framebuffer->size.width;
-		render_pass_begin.renderArea.extent.height = framebuffer->size.height;
-		render_pass_begin.renderArea.offset.x = 0;
-		render_pass_begin.renderArea.offset.y = 0;
-	}
-
-	Vector<VkClearValue> clear_values;
-	clear_values.resize(framebuffer->texture_ids.size());
-	int clear_values_count = 0;
-	{
-		int color_index = 0;
-		for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
-			VkClearValue clear_value;
-
-			Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-			if (!texture) {
-				color_index++;
-				continue;
-			}
-
-			if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-				ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
-				Color clear_color = p_clear_colors[color_index];
-				clear_value.color.float32[0] = clear_color.r;
-				clear_value.color.float32[1] = clear_color.g;
-				clear_value.color.float32[2] = clear_color.b;
-				clear_value.color.float32[3] = clear_color.a;
-				color_index++;
-			} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-				clear_value.depthStencil.depth = p_clear_depth;
-				clear_value.depthStencil.stencil = p_clear_stencil;
-			} else {
-				clear_value.color.float32[0] = 0;
-				clear_value.color.float32[1] = 0;
-				clear_value.color.float32[2] = 0;
-				clear_value.color.float32[3] = 0;
-			}
-			clear_values.write[clear_values_count++] = clear_value;
-		}
-	}
-
-	render_pass_begin.clearValueCount = clear_values_count;
-	render_pass_begin.pClearValues = clear_values.ptr();
-
-	for (int i = 0; i < p_storage_textures.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(p_storage_textures[i]);
-		if (!texture) {
-			continue;
-		}
-		ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage.");
-
-		if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
-			// Must change layout to general.
-			VkImageMemoryBarrier image_memory_barrier;
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.oldLayout = texture->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = texture->image;
-			image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = texture->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = texture->layers;
-
-			vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-
-			texture->layout = VK_IMAGE_LAYOUT_GENERAL;
-
-			draw_list_storage_textures.push_back(p_storage_textures[i]);
-		}
-	}
-
-	vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents);
-
-	// Mark textures as bound.
-	draw_list_bound_textures.clear();
-	draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
-	draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
-
-	for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-		if (!texture) {
-			continue;
-		}
-		texture->bound = true;
-		draw_list_bound_textures.push_back(framebuffer->texture_ids[i]);
-	}
-
-	return OK;
-}
-
-void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
-	Vector<VkClearAttachment> clear_attachments;
-	int color_index = 0;
-	int texture_index = 0;
-	for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
-
-		if (!texture) {
-			texture_index++;
-			continue;
-		}
-
-		VkClearAttachment clear_at = {};
-		if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-			Color clear_color = p_clear_colors[texture_index++];
-			clear_at.clearValue.color.float32[0] = clear_color.r;
-			clear_at.clearValue.color.float32[1] = clear_color.g;
-			clear_at.clearValue.color.float32[2] = clear_color.b;
-			clear_at.clearValue.color.float32[3] = clear_color.a;
-			clear_at.colorAttachment = color_index++;
-			clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-		} else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-			clear_at.clearValue.depthStencil.depth = p_depth;
-			clear_at.clearValue.depthStencil.stencil = p_stencil;
-			clear_at.colorAttachment = 0;
-			clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-			if (format_has_stencil(texture->format)) {
-				clear_at.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
-			}
-		} else {
-			ERR_CONTINUE(true);
-		}
-		clear_attachments.push_back(clear_at);
-	}
-
-	VkClearRect cr;
-	cr.baseArrayLayer = 0;
-	cr.layerCount = 1;
-	cr.rect.offset.x = p_viewport_offset.x;
-	cr.rect.offset.y = p_viewport_offset.y;
-	cr.rect.extent.width = p_viewport_size.width;
-	cr.rect.extent.height = p_viewport_size.height;
-
-	vkCmdClearAttachments(p_draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
-}
-
-RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
-
-	Point2i viewport_offset;
-	Point2i viewport_size = framebuffer->size;
-	bool constrained_to_region = false;
-	bool needs_clear_color = false;
-	bool needs_clear_depth = false;
-
-	if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
-		Rect2i viewport(viewport_offset, viewport_size);
-		Rect2i regioni = p_region;
-		if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
-				((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) &&
-				((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) {
-			ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle");
-		}
-
-		viewport_offset = regioni.position;
-		viewport_size = regioni.size;
-
-		// If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
-		// and we constrain the render area to the region.
-		if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
-			constrained_to_region = true;
-			p_initial_color_action = INITIAL_ACTION_CLEAR;
-			p_initial_depth_action = INITIAL_ACTION_CLEAR;
-		} else {
-			if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
-				needs_clear_color = true;
-				p_initial_color_action = INITIAL_ACTION_CONTINUE;
-			}
-			if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
-				needs_clear_depth = true;
-				p_initial_depth_action = INITIAL_ACTION_CONTINUE;
-			}
-			if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
-				needs_clear_color = true;
-				p_initial_color_action = INITIAL_ACTION_KEEP;
-			}
-			if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
-				needs_clear_depth = true;
-				p_initial_depth_action = INITIAL_ACTION_KEEP;
-			}
-		}
-	}
-
-	if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
-		int color_count = 0;
-		for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
-			Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-			// We only check for our VRS usage bit if this is not the first texture id.
-			// If it is the first we're likely populating our VRS texture.
-			// Bit dirty but...
-			if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) {
-				if (!texture || !texture->is_resolve_buffer) {
-					color_count++;
-				}
-			}
-		}
-		ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
-	}
-
-	VkFramebuffer vkframebuffer;
-	VkRenderPass render_pass;
-
-	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count);
-	ERR_FAIL_COND_V(err != OK, INVALID_ID);
-
-	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-	err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE, p_storage_textures, constrained_to_region);
-
-	if (err != OK) {
-		return INVALID_ID;
-	}
-
-	draw_list_render_pass = render_pass;
-	draw_list_vkframebuffer = vkframebuffer;
-
-	_draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0, 0);
-#ifdef DEBUG_ENABLED
-	draw_list_framebuffer_format = framebuffer->format_id;
-#endif
-	draw_list_current_subpass = 0;
-
-	if (needs_clear_color || needs_clear_depth) {
-		DEV_ASSERT(!constrained_to_region);
-		_draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
-	}
-
-	VkViewport viewport;
-	viewport.x = viewport_offset.x;
-	viewport.y = viewport_offset.y;
-	viewport.width = viewport_size.width;
-	viewport.height = viewport_size.height;
-	viewport.minDepth = 0;
-	viewport.maxDepth = 1.0;
-
-	vkCmdSetViewport(command_buffer, 0, 1, &viewport);
-
-	VkRect2D scissor;
-	scissor.offset.x = viewport_offset.x;
-	scissor.offset.y = viewport_offset.y;
-	scissor.extent.width = viewport_size.width;
-	scissor.extent.height = viewport_size.height;
-
-	vkCmdSetScissor(command_buffer, 0, 1, &scissor);
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-
-Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time.");
-
-	ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION);
-
-	Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
-	ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION);
-
-	Point2i viewport_offset;
-	Point2i viewport_size = framebuffer->size;
-
-	bool constrained_to_region = false;
-	bool needs_clear_color = false;
-	bool needs_clear_depth = false;
-
-	if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
-		Rect2i viewport(viewport_offset, viewport_size);
-		Rect2i regioni = p_region;
-		if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
-				((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) &&
-				((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) {
-			ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle");
-		}
-
-		viewport_offset = regioni.position;
-		viewport_size = regioni.size;
-
-		// If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
-		// and we constrain the render area to the region.
-		if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
-			constrained_to_region = true;
-			p_initial_color_action = INITIAL_ACTION_CLEAR;
-			p_initial_depth_action = INITIAL_ACTION_CLEAR;
-		} else {
-			if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
-				needs_clear_color = true;
-				p_initial_color_action = INITIAL_ACTION_CONTINUE;
-			}
-			if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
-				needs_clear_depth = true;
-				p_initial_depth_action = INITIAL_ACTION_CONTINUE;
-			}
-			if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
-				needs_clear_color = true;
-				p_initial_color_action = INITIAL_ACTION_KEEP;
-			}
-			if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
-				needs_clear_depth = true;
-				p_initial_depth_action = INITIAL_ACTION_KEEP;
-			}
-		}
-	}
-
-	if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
-
-		int color_count = 0;
-		for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
-			Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-
-			if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-				color_count++;
-			}
-		}
-
-		ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, ERR_INVALID_PARAMETER,
-				"Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_count) + ").");
-	}
-
-	VkFramebuffer vkframebuffer;
-	VkRenderPass render_pass;
-
-	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count);
-	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-
-	VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer;
-	err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, p_storage_textures, constrained_to_region);
-
-	if (err != OK) {
-		return ERR_CANT_CREATE;
-	}
-
-	draw_list_current_subpass = 0;
-
-#ifdef DEBUG_ENABLED
-	draw_list_framebuffer_format = framebuffer->format_id;
-#endif
-	draw_list_render_pass = render_pass;
-	draw_list_vkframebuffer = vkframebuffer;
-
-	err = _draw_list_allocate(Rect2i(viewport_offset, viewport_size), p_splits, 0);
-	if (err != OK) {
-		return err;
-	}
-
-	if (needs_clear_color || needs_clear_depth) {
-		DEV_ASSERT(!constrained_to_region);
-		_draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
-	}
-
-	for (uint32_t i = 0; i < p_splits; i++) {
-		VkViewport viewport;
-		viewport.x = viewport_offset.x;
-		viewport.y = viewport_offset.y;
-		viewport.width = viewport_size.width;
-		viewport.height = viewport_size.height;
-		viewport.minDepth = 0;
-		viewport.maxDepth = 1.0;
-
-		vkCmdSetViewport(draw_list[i].command_buffer, 0, 1, &viewport);
-
-		VkRect2D scissor;
-		scissor.offset.x = viewport_offset.x;
-		scissor.offset.y = viewport_offset.y;
-		scissor.extent.width = viewport_size.width;
-		scissor.extent.height = viewport_size.height;
-
-		vkCmdSetScissor(draw_list[i].command_buffer, 0, 1, &scissor);
-		r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
-	}
-
-	return OK;
-}
-
-RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) {
-	if (p_id < 0) {
-		return nullptr;
-	}
-
-	if (!draw_list) {
-		return nullptr;
-	} else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) {
-		if (draw_list_split) {
-			return nullptr;
-		}
-		return draw_list;
-	} else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) {
-		if (!draw_list_split) {
-			return nullptr;
-		}
-
-		uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
-
-		if (index >= draw_list_count) {
-			return nullptr;
-		}
-
-		return &draw_list[index];
-	} else {
-		return nullptr;
-	}
-}
-
-void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	vkCmdSetBlendConstants(dl->command_buffer, p_color.components);
-}
-
-void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline);
-	ERR_FAIL_NULL(pipeline);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass);
-#endif
-
-	if (p_render_pipeline == dl->state.pipeline) {
-		return; // Redundant state, return.
-	}
-
-	dl->state.pipeline = p_render_pipeline;
-	dl->state.pipeline_layout = pipeline->pipeline_layout;
-
-	vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
-
-	if (dl->state.pipeline_shader != pipeline->shader) {
-		// Shader changed, so descriptor sets may become incompatible.
-
-		// Go through ALL sets, and unbind them (and all those above) if the format is different.
-
-		uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
-		dl->state.set_count = MAX(dl->state.set_count, pcount);
-		const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
-
-		bool sets_valid = true; // Once invalid, all above become invalid.
-		for (uint32_t i = 0; i < pcount; i++) {
-			// If a part of the format is different, invalidate it (and the rest).
-			if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) {
-				dl->state.sets[i].bound = false;
-				dl->state.sets[i].pipeline_expected_format = pformats[i];
-				sets_valid = false;
-			}
-		}
-
-		for (uint32_t i = pcount; i < dl->state.set_count; i++) {
-			// Unbind the ones above (not used) if exist.
-			dl->state.sets[i].bound = false;
-		}
-
-		dl->state.set_count = pcount; // Update set count.
-
-		if (pipeline->push_constant_size) {
-			dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
-#ifdef DEBUG_ENABLED
-			dl->validation.pipeline_push_constant_supplied = false;
-#endif
-		}
-
-		dl->state.pipeline_shader = pipeline->shader;
-	}
-
-#ifdef DEBUG_ENABLED
-	// Update render pass pipeline info.
-	dl->validation.pipeline_active = true;
-	dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;
-	dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format;
-	dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices;
-	dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor;
-	dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum;
-	dl->validation.pipeline_push_constant_size = pipeline->push_constant_size;
-#endif
-}
-
-void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) {
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS,
-			"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ").");
-#endif
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(uniform_set);
-
-	if (p_index > dl->state.set_count) {
-		dl->state.set_count = p_index;
-	}
-
-	dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
-	dl->state.sets[p_index].bound = false; // Needs rebind.
-	dl->state.sets[p_index].uniform_set_format = uniform_set->format;
-	dl->state.sets[p_index].uniform_set = p_uniform_set;
-
-	uint32_t mst_count = uniform_set->mutable_storage_textures.size();
-	if (mst_count) {
-		Texture **mst_textures = const_cast<UniformSet *>(uniform_set)->mutable_storage_textures.ptrw();
-		for (uint32_t i = 0; i < mst_count; i++) {
-			if (mst_textures[i]->used_in_frame != frames_drawn) {
-				mst_textures[i]->used_in_frame = frames_drawn;
-				mst_textures[i]->used_in_transfer = false;
-				mst_textures[i]->used_in_compute = false;
-			}
-			mst_textures[i]->used_in_raster = true;
-		}
-	}
-
-#ifdef DEBUG_ENABLED
-	{ // Validate that textures bound are not attached as framebuffer bindings.
-		uint32_t attachable_count = uniform_set->attachable_textures.size();
-		const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();
-		uint32_t bound_count = draw_list_bound_textures.size();
-		const RID *bound_ptr = draw_list_bound_textures.ptr();
-		for (uint32_t i = 0; i < attachable_count; i++) {
-			for (uint32_t j = 0; j < bound_count; j++) {
-				ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j],
-						"Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed.");
-			}
-		}
-	}
-#endif
-}
-
-void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);
-	ERR_FAIL_NULL(vertex_array);
-
-	if (dl->state.vertex_array == p_vertex_array) {
-		return; // Already set.
-	}
-
-	dl->state.vertex_array = p_vertex_array;
-
-#ifdef DEBUG_ENABLED
-	dl->validation.vertex_format = vertex_array->description;
-	dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed;
-#endif
-	dl->validation.vertex_array_size = vertex_array->vertex_count;
-	vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr());
-}
-
-void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	const IndexArray *index_array = index_array_owner.get_or_null(p_index_array);
-	ERR_FAIL_NULL(index_array);
-
-	if (dl->state.index_array == p_index_array) {
-		return; // Already set.
-	}
-
-	dl->state.index_array = p_index_array;
-#ifdef DEBUG_ENABLED
-	dl->validation.index_array_max_index = index_array->max_index;
-#endif
-	dl->validation.index_array_size = index_array->indices;
-	dl->validation.index_array_offset = index_array->offset;
-
-	vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, 0, index_array->index_type);
-}
-
-void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	vkCmdSetLineWidth(dl->command_buffer, p_width);
-}
-
-void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size,
-			"This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
-#endif
-	vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data);
-#ifdef DEBUG_ENABLED
-	dl->validation.pipeline_push_constant_supplied = true;
-#endif
-}
-
-void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
-			"No render pipeline was set before attempting to draw.");
-	if (dl->validation.pipeline_vertex_format != INVALID_ID) {
-		// Pipeline uses vertices, validate format.
-		ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
-				"No vertex array was bound, and render pipeline expects vertices.");
-		// Make sure format is right.
-		ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format,
-				"The vertex format used to create the pipeline does not match the vertex format bound.");
-		// Make sure number of instances is valid.
-		ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed,
-				"Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ").");
-	}
-
-	if (dl->validation.pipeline_push_constant_size > 0) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	// Bind descriptor sets.
-
-	for (uint32_t i = 0; i < dl->state.set_count; i++) {
-		if (dl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
-			if (dl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
-			}
-		}
-#endif
-		if (!dl->state.sets[i].bound) {
-			// All good, see if this requires re-binding.
-			vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, nullptr);
-			dl->state.sets[i].bound = true;
-		}
-	}
-
-	if (p_use_indices) {
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(p_procedural_vertices > 0,
-				"Procedural vertices can't be used together with indices.");
-
-		ERR_FAIL_COND_MSG(!dl->validation.index_array_size,
-				"Draw command requested indices, but no index buffer was set.");
-
-		ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
-				"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
-#endif
-		uint32_t to_draw = dl->validation.index_array_size;
-
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
-				"Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ").");
-
-		ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
-				"Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
-#endif
-		vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0);
-	} else {
-		uint32_t to_draw;
-
-		if (p_procedural_vertices > 0) {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != INVALID_ID,
-					"Procedural vertices requested, but pipeline expects a vertex array.");
-#endif
-			to_draw = p_procedural_vertices;
-		} else {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID,
-					"Draw command lacks indices, but pipeline format does not use vertices.");
-#endif
-			to_draw = dl->validation.vertex_array_size;
-		}
-
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
-				"Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ").");
-
-		ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
-				"Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
-#endif
-
-		vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0);
-	}
-}
-
-void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-	Rect2i rect = p_rect;
-	rect.position += dl->viewport.position;
-
-	rect = dl->viewport.intersection(rect);
-
-	if (rect.get_area() == 0) {
-		return;
-	}
-	VkRect2D scissor;
-	scissor.offset.x = rect.position.x;
-	scissor.offset.y = rect.position.y;
-	scissor.extent.width = rect.size.width;
-	scissor.extent.height = rect.size.height;
-
-	vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor);
-}
-
-void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) {
-	DrawList *dl = _get_draw_list_ptr(p_list);
-	ERR_FAIL_NULL(dl);
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
-#endif
-
-	VkRect2D scissor;
-	scissor.offset.x = dl->viewport.position.x;
-	scissor.offset.y = dl->viewport.position.y;
-	scissor.extent.width = dl->viewport.size.width;
-	scissor.extent.height = dl->viewport.size.height;
-	vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor);
-}
-
-uint32_t RenderingDeviceVulkan::draw_list_get_current_pass() {
-	return draw_list_current_subpass;
-}
-
-RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_NULL_V(draw_list, INVALID_ID);
-	ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);
-
-	draw_list_current_subpass++;
-
-	Rect2i viewport;
-	_draw_list_free(&viewport);
-
-	vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE);
-
-	_draw_list_allocate(viewport, 0, draw_list_current_subpass);
-
-	return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
-}
-Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {
-	_THREAD_SAFE_METHOD_
-	ERR_FAIL_NULL_V(draw_list, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER);
-
-	draw_list_current_subpass++;
-
-	Rect2i viewport;
-	_draw_list_free(&viewport);
-
-	vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE);
-
-	_draw_list_allocate(viewport, p_splits, draw_list_current_subpass);
-
-	for (uint32_t i = 0; i < p_splits; i++) {
-		r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
-	}
-
-	return OK;
-}
-
-Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) {
-	// Lock while draw_list is active.
-	_THREAD_SAFE_LOCK_
-
-	if (p_splits == 0) {
-		draw_list = memnew(DrawList);
-		draw_list->command_buffer = frames[frame].draw_command_buffer;
-		draw_list->viewport = p_viewport;
-		draw_list_count = 0;
-		draw_list_split = false;
-	} else {
-		if (p_splits > (uint32_t)split_draw_list_allocators.size()) {
-			uint32_t from = split_draw_list_allocators.size();
-			split_draw_list_allocators.resize(p_splits);
-			for (uint32_t i = from; i < p_splits; i++) {
-				VkCommandPoolCreateInfo cmd_pool_info;
-				cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
-				cmd_pool_info.pNext = nullptr;
-				cmd_pool_info.queueFamilyIndex = context->get_graphics_queue_family_index();
-				cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-
-				VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &split_draw_list_allocators.write[i].command_pool);
-				ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + ".");
-
-				for (int j = 0; j < frame_count; j++) {
-					VkCommandBuffer command_buffer;
-
-					VkCommandBufferAllocateInfo cmdbuf;
-					// No command buffer exists, create it.
-					cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-					cmdbuf.pNext = nullptr;
-					cmdbuf.commandPool = split_draw_list_allocators[i].command_pool;
-					cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
-					cmdbuf.commandBufferCount = 1;
-
-					VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer);
-					ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkAllocateCommandBuffers failed with error " + itos(err) + ".");
-
-					split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer);
-				}
-			}
-		}
-		draw_list = memnew_arr(DrawList, p_splits);
-		draw_list_count = p_splits;
-		draw_list_split = true;
-
-		for (uint32_t i = 0; i < p_splits; i++) {
-			// Take a command buffer and initialize it.
-			VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame];
-
-			VkCommandBufferInheritanceInfo inheritance_info;
-			inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
-			inheritance_info.pNext = nullptr;
-			inheritance_info.renderPass = draw_list_render_pass;
-			inheritance_info.subpass = p_subpass;
-			inheritance_info.framebuffer = draw_list_vkframebuffer;
-			inheritance_info.occlusionQueryEnable = false;
-			inheritance_info.queryFlags = 0; // ?
-			inheritance_info.pipelineStatistics = 0;
-
-			VkCommandBufferBeginInfo cmdbuf_begin;
-			cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-			cmdbuf_begin.pNext = nullptr;
-			cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
-			cmdbuf_begin.pInheritanceInfo = &inheritance_info;
-
-			VkResult res = vkResetCommandBuffer(command_buffer, 0);
-			if (res) {
-				memdelete_arr(draw_list);
-				draw_list = nullptr;
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkResetCommandBuffer failed with error " + itos(res) + ".");
-			}
-
-			res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin);
-			if (res) {
-				memdelete_arr(draw_list);
-				draw_list = nullptr;
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkBeginCommandBuffer failed with error " + itos(res) + ".");
-			}
-
-			draw_list[i].command_buffer = command_buffer;
-			draw_list[i].viewport = p_viewport;
-		}
-	}
-
-	return OK;
-}
-
-void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
-	if (draw_list_split) {
-		// Send all command buffers.
-		VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count);
-		for (uint32_t i = 0; i < draw_list_count; i++) {
-			vkEndCommandBuffer(draw_list[i].command_buffer);
-			command_buffers[i] = draw_list[i].command_buffer;
-			if (r_last_viewport) {
-				if (i == 0 || draw_list[i].viewport_set) {
-					*r_last_viewport = draw_list[i].viewport;
-				}
-			}
-		}
-
-		vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers);
-		memdelete_arr(draw_list);
-		draw_list = nullptr;
-
-	} else {
-		if (r_last_viewport) {
-			*r_last_viewport = draw_list->viewport;
-		}
-		// Just end the list.
-		memdelete(draw_list);
-		draw_list = nullptr;
-	}
-
-	// Draw_list is no longer active.
-	_THREAD_SAFE_UNLOCK_
-}
-
-void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_NULL_MSG(draw_list, "Immediate draw list is already inactive.");
-
-	_draw_list_free();
-
-	vkCmdEndRenderPass(frames[frame].draw_command_buffer);
-
-	for (int i = 0; i < draw_list_bound_textures.size(); i++) {
-		Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);
-		ERR_CONTINUE(!texture); // Wtf.
-		if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
-			texture->bound = false;
-		}
-		if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-			texture->bound = false;
-		}
-	}
-
-	uint32_t barrier_flags = 0;
-	uint32_t access_flags = 0;
-	if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-		barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-		barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-		barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-		barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
-	}
-
-	if (barrier_flags == 0) {
-		barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-	}
-
-	draw_list_bound_textures.clear();
-
-	VkImageMemoryBarrier *image_barriers = nullptr;
-
-	uint32_t image_barrier_count = draw_list_storage_textures.size();
-
-	if (image_barrier_count) {
-		image_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * draw_list_storage_textures.size());
-	}
-
-	uint32_t src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
-			VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-	uint32_t src_access =
-			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
-	if (image_barrier_count) {
-		src_stage |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		src_access |= VK_ACCESS_SHADER_WRITE_BIT;
-	}
-
-	for (uint32_t i = 0; i < image_barrier_count; i++) {
-		Texture *texture = texture_owner.get_or_null(draw_list_storage_textures[i]);
-
-		VkImageMemoryBarrier &image_memory_barrier = image_barriers[i];
-		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		image_memory_barrier.pNext = nullptr;
-		image_memory_barrier.srcAccessMask = src_access;
-		image_memory_barrier.dstAccessMask = access_flags;
-		image_memory_barrier.oldLayout = texture->layout;
-		image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		image_memory_barrier.image = texture->image;
-		image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask;
-		image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap;
-		image_memory_barrier.subresourceRange.levelCount = texture->mipmaps;
-		image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer;
-		image_memory_barrier.subresourceRange.layerCount = texture->layers;
-
-		texture->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-	}
-
-	draw_list_storage_textures.clear();
-
-	// To ensure proper synchronization, we must make sure rendering is done before:
-	// * Some buffer is copied.
-	// * Another render pass happens (since we may be done).
-
-	VkMemoryBarrier mem_barrier;
-	mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-	mem_barrier.pNext = nullptr;
-	mem_barrier.srcAccessMask = src_access;
-	mem_barrier.dstAccessMask = access_flags;
-
-	if (image_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) {
-		vkCmdPipelineBarrier(frames[frame].draw_command_buffer, src_stage, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
-	}
-
-#ifdef FORCE_FULL_BARRIER
-	_full_barrier(true);
-#endif
-}
-
-/***********************/
-/**** COMPUTE LISTS ****/
-/***********************/
-
-RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_allow_draw_overlap) {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
-	ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
-
-	// Lock while compute_list is active.
-	_THREAD_SAFE_LOCK_
-
-	compute_list = memnew(ComputeList);
-	compute_list->command_buffer = frames[frame].draw_command_buffer;
-	compute_list->state.allow_draw_overlap = p_allow_draw_overlap;
-
-	return ID_TYPE_COMPUTE_LIST;
-}
-
-void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-	const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline);
-	ERR_FAIL_NULL(pipeline);
-
-	if (p_compute_pipeline == cl->state.pipeline) {
-		return; // Redundant state, return.
-	}
-
-	cl->state.pipeline = p_compute_pipeline;
-	cl->state.pipeline_layout = pipeline->pipeline_layout;
-
-	vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline);
-
-	if (cl->state.pipeline_shader != pipeline->shader) {
-		// Shader changed, so descriptor sets may become incompatible.
-
-		// Go through ALL sets, and unbind them (and all those above) if the format is different.
-
-		uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
-		cl->state.set_count = MAX(cl->state.set_count, pcount);
-		const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
-
-		bool sets_valid = true; // Once invalid, all above become invalid.
-		for (uint32_t i = 0; i < pcount; i++) {
-			// If a part of the format is different, invalidate it (and the rest).
-			if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) {
-				cl->state.sets[i].bound = false;
-				cl->state.sets[i].pipeline_expected_format = pformats[i];
-				sets_valid = false;
-			}
-		}
-
-		for (uint32_t i = pcount; i < cl->state.set_count; i++) {
-			// Unbind the ones above (not used) if exist.
-			cl->state.sets[i].bound = false;
-		}
-
-		cl->state.set_count = pcount; // Update set count.
-
-		if (pipeline->push_constant_size) {
-			cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
-#ifdef DEBUG_ENABLED
-			cl->validation.pipeline_push_constant_supplied = false;
-#endif
-		}
-
-		cl->state.pipeline_shader = pipeline->shader;
-		cl->state.local_group_size[0] = pipeline->local_group_size[0];
-		cl->state.local_group_size[1] = pipeline->local_group_size[1];
-		cl->state.local_group_size[2] = pipeline->local_group_size[2];
-	}
-
-#ifdef DEBUG_ENABLED
-	// Update compute pass pipeline info.
-	cl->validation.pipeline_active = true;
-	cl->validation.pipeline_push_constant_size = pipeline->push_constant_size;
-#endif
-}
-
-void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS,
-			"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ").");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-	UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
-	ERR_FAIL_NULL(uniform_set);
-
-	if (p_index > cl->state.set_count) {
-		cl->state.set_count = p_index;
-	}
-
-	cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
-	cl->state.sets[p_index].bound = false; // Needs rebind.
-	cl->state.sets[p_index].uniform_set_format = uniform_set->format;
-	cl->state.sets[p_index].uniform_set = p_uniform_set;
-
-	uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size();
-	uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size();
-
-	Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw();
-
-	VkImageMemoryBarrier *texture_barriers = nullptr;
-
-	if (textures_to_sampled_count + textures_to_storage_count) {
-		texture_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * (textures_to_sampled_count + textures_to_storage_count));
-	}
-	uint32_t texture_barrier_count = 0;
-
-	uint32_t src_stage_flags = 0;
-
-	for (uint32_t i = 0; i < textures_to_sampled_count; i++) {
-		if (textures_to_sampled[i]->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
-			src_stage_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-
-			VkImageMemoryBarrier &image_memory_barrier = texture_barriers[texture_barrier_count++];
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.oldLayout = textures_to_sampled[i]->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = textures_to_sampled[i]->image;
-			image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = textures_to_sampled[i]->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_sampled[i]->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers;
-
-			textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-			cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]);
-		}
-
-		if (textures_to_sampled[i]->used_in_frame != frames_drawn) {
-			textures_to_sampled[i]->used_in_frame = frames_drawn;
-			textures_to_sampled[i]->used_in_transfer = false;
-			textures_to_sampled[i]->used_in_raster = false;
-		}
-		textures_to_sampled[i]->used_in_compute = true;
-	}
-
-	Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw();
-
-	for (uint32_t i = 0; i < textures_to_storage_count; i++) {
-		if (textures_to_storage[i]->layout != VK_IMAGE_LAYOUT_GENERAL) {
-			uint32_t src_access_flags = 0;
-
-			if (textures_to_storage[i]->used_in_frame == frames_drawn) {
-				if (textures_to_storage[i]->used_in_compute) {
-					src_stage_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-					src_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-				}
-				if (textures_to_storage[i]->used_in_raster) {
-					src_stage_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-					src_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-				}
-				if (textures_to_storage[i]->used_in_transfer) {
-					src_stage_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-					src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
-				}
-
-				textures_to_storage[i]->used_in_compute = false;
-				textures_to_storage[i]->used_in_raster = false;
-				textures_to_storage[i]->used_in_transfer = false;
-
-			} else {
-				src_access_flags = 0;
-				textures_to_storage[i]->used_in_compute = false;
-				textures_to_storage[i]->used_in_raster = false;
-				textures_to_storage[i]->used_in_transfer = false;
-				textures_to_storage[i]->used_in_frame = frames_drawn;
-			}
-
-			VkImageMemoryBarrier &image_memory_barrier = texture_barriers[texture_barrier_count++];
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = src_access_flags;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.oldLayout = textures_to_storage[i]->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = textures_to_storage[i]->image;
-			image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = textures_to_storage[i]->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_storage[i]->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers;
-
-			textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL;
-
-			cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards.
-		}
-	}
-
-	if (texture_barrier_count) {
-		if (src_stage_flags == 0) {
-			src_stage_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-		}
-
-		vkCmdPipelineBarrier(cl->command_buffer, src_stage_flags, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, texture_barrier_count, texture_barriers);
-	}
-
-#if 0
-	{ // Validate that textures bound are not attached as framebuffer bindings.
-		uint32_t attachable_count = uniform_set->attachable_textures.size();
-		const RID *attachable_ptr = uniform_set->attachable_textures.ptr();
-		uint32_t bound_count = draw_list_bound_textures.size();
-		const RID *bound_ptr = draw_list_bound_textures.ptr();
-		for (uint32_t i = 0; i < attachable_count; i++) {
-			for (uint32_t j = 0; j < bound_count; j++) {
-				ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j],
-						"Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed.");
-			}
-		}
-	}
-#endif
-}
-
-void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size,
-			"This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
-#endif
-	vkCmdPushConstants(cl->command_buffer, cl->state.pipeline_layout, cl->state.pipeline_push_constant_stages, 0, p_data_size, p_data);
-#ifdef DEBUG_ENABLED
-	cl->validation.pipeline_push_constant_supplied = true;
-#endif
-}
-
-void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_x_groups == 0, "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_z_groups == 0, "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_y_groups == 0, "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_x_groups > limits.maxComputeWorkGroupCount[0],
-			"Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")");
-	ERR_FAIL_COND_MSG(p_y_groups > limits.maxComputeWorkGroupCount[1],
-			"Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[1]) + ")");
-	ERR_FAIL_COND_MSG(p_z_groups > limits.maxComputeWorkGroupCount[2],
-			"Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[2]) + ")");
-
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_push_constant_size > 0) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	// Bind descriptor sets.
-
-	for (uint32_t i = 0; i < cl->state.set_count; i++) {
-		if (cl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
-			if (cl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			}
-		}
-#endif
-		if (!cl->state.sets[i].bound) {
-			// All good, see if this requires re-binding.
-			vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr);
-			cl->state.sets[i].bound = true;
-		}
-	}
-
-	vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups);
-}
-
-void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_y_threads == 0, "Dispatch amount of Y compute threads (" + itos(p_y_threads) + ") is zero.");
-	ERR_FAIL_COND_MSG(p_z_threads == 0, "Dispatch amount of Z compute threads (" + itos(p_z_threads) + ") is zero.");
-#endif
-
-	ComputeList *cl = compute_list;
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_push_constant_size > 0) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	compute_list_dispatch(p_list, (p_x_threads - 1) / cl->state.local_group_size[0] + 1, (p_y_threads - 1) / cl->state.local_group_size[1] + 1, (p_z_threads - 1) / cl->state.local_group_size[2] + 1);
-}
-
-void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) {
-	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
-	ERR_FAIL_NULL(compute_list);
-
-	ComputeList *cl = compute_list;
-	Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);
-	ERR_FAIL_NULL(buffer);
-
-	ERR_FAIL_COND_MSG(!(buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), "Buffer provided was not created to do indirect dispatch.");
-
-	ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer.");
-
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
-#endif
-
-#ifdef DEBUG_ENABLED
-
-	ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
-
-	if (cl->validation.pipeline_push_constant_size > 0) {
-		// Using push constants, check that they were supplied.
-		ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
-				"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
-	}
-
-#endif
-
-	// Bind descriptor sets.
-
-	for (uint32_t i = 0; i < cl->state.set_count; i++) {
-		if (cl->state.sets[i].pipeline_expected_format == 0) {
-			continue; // Nothing expected by this pipeline.
-		}
-#ifdef DEBUG_ENABLED
-		if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
-			if (cl->state.sets[i].uniform_set_format == 0) {
-				ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
-			} else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) {
-				UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			} else {
-				ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
-			}
-		}
-#endif
-		if (!cl->state.sets[i].bound) {
-			// All good, see if this requires re-binding.
-			vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr);
-			cl->state.sets[i].bound = true;
-		}
-	}
-
-	vkCmdDispatchIndirect(cl->command_buffer, buffer->buffer, p_offset);
-}
-
-void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
-	// Must be called within a compute list, the class mutex is locked during that time
-
-	uint32_t barrier_flags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-	uint32_t access_flags = VK_ACCESS_SHADER_READ_BIT;
-	_compute_list_add_barrier(BARRIER_MASK_COMPUTE, barrier_flags, access_flags);
-}
-
-void RenderingDeviceVulkan::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags) {
-	ERR_FAIL_NULL(compute_list);
-
-	VkImageMemoryBarrier *image_barriers = nullptr;
-
-	uint32_t image_barrier_count = compute_list->state.textures_to_sampled_layout.size();
-
-	if (image_barrier_count) {
-		image_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * image_barrier_count);
-	}
-
-	image_barrier_count = 0; // We'll count how many we end up issuing.
-
-	for (Texture *E : compute_list->state.textures_to_sampled_layout) {
-		if (E->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
-			VkImageMemoryBarrier &image_memory_barrier = image_barriers[image_barrier_count++];
-			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-			image_memory_barrier.pNext = nullptr;
-			image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = p_access_flags;
-			image_memory_barrier.oldLayout = E->layout;
-			image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			image_memory_barrier.image = E->image;
-			image_memory_barrier.subresourceRange.aspectMask = E->read_aspect_mask;
-			image_memory_barrier.subresourceRange.baseMipLevel = E->base_mipmap;
-			image_memory_barrier.subresourceRange.levelCount = E->mipmaps;
-			image_memory_barrier.subresourceRange.baseArrayLayer = E->base_layer;
-			image_memory_barrier.subresourceRange.layerCount = E->layers;
-
-			E->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-		}
-
-		if (E->used_in_frame != frames_drawn) {
-			E->used_in_transfer = false;
-			E->used_in_raster = false;
-			E->used_in_compute = false;
-			E->used_in_frame = frames_drawn;
-		}
-	}
-
-	if (p_barrier_flags) {
-		VkMemoryBarrier mem_barrier;
-		mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-		mem_barrier.pNext = nullptr;
-		mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
-		mem_barrier.dstAccessMask = p_access_flags;
-		vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
-	} else if (image_barrier_count) {
-		vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, image_barrier_count, image_barriers);
-	}
-
-#ifdef FORCE_FULL_BARRIER
-	_full_barrier(true);
-#endif
-}
-
-void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) {
-	ERR_FAIL_NULL(compute_list);
-
-	uint32_t barrier_flags = 0;
-	uint32_t access_flags = 0;
-	if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
-		barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
-		barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
-		barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
-		access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
-	}
-	if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
-		barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
-	}
-	_compute_list_add_barrier(p_post_barrier, barrier_flags, access_flags);
-
-	memdelete(compute_list);
-	compute_list = nullptr;
-
-	// Compute_list is no longer active.
-	_THREAD_SAFE_UNLOCK_
-}
-
-void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
-	uint32_t src_barrier_flags = 0;
-	uint32_t src_access_flags = 0;
-
-	if (p_from == 0) {
-		src_barrier_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-	} else {
-		if (p_from.has_flag(BARRIER_MASK_COMPUTE)) {
-			src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) {
-			src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
-					VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
-					VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-			src_access_flags |=
-					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-		}
-		if (p_from.has_flag(BARRIER_MASK_TRANSFER)) {
-			src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-	}
-
-	uint32_t dst_barrier_flags = 0;
-	uint32_t dst_access_flags = 0;
-
-	if (p_to == 0) {
-		dst_barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-	} else {
-		if (p_to.has_flag(BARRIER_MASK_COMPUTE)) {
-			dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-			dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
-		}
-		if (p_to.has_flag(BARRIER_MASK_VERTEX)) {
-			dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
-			dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
-		}
-		if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) {
-			dst_barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
-			dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
-		}
-		if (p_to.has_flag(BARRIER_MASK_TRANSFER)) {
-			dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-			dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
-		}
-	}
-
-	_memory_barrier(src_barrier_flags, dst_barrier_flags, src_access_flags, dst_access_flags, true);
-}
-
-void RenderingDeviceVulkan::full_barrier() {
-#ifndef DEBUG_ENABLED
-	ERR_PRINT("Full barrier is debug-only, should not be used in production");
-#endif
-	_full_barrier(true);
-}
-
-#if 0
-void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Variant> &p_clear_colors) {
-	VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer;
-	ERR_FAIL_NULL(frame_cmdbuf);
-
-	VkRenderPassBeginInfo render_pass_begin;
-	render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-	render_pass_begin.pNext = nullptr;
-	render_pass_begin.renderPass = context->get_render_pass();
-	render_pass_begin.framebuffer = context->get_frame_framebuffer(frame);
-
-	render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen);
-	render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen);
-	render_pass_begin.renderArea.offset.x = 0;
-	render_pass_begin.renderArea.offset.y = 0;
-
-	render_pass_begin.clearValueCount = 1;
-
-	VkClearValue clear_value;
-	clear_value.color.float32[0] = p_clear_color.r;
-	clear_value.color.float32[1] = p_clear_color.g;
-	clear_value.color.float32[2] = p_clear_color.b;
-	clear_value.color.float32[3] = p_clear_color.a;
-
-	render_pass_begin.pClearValues = &clear_value;
-
-	vkCmdBeginRenderPass(frame_cmdbuf, &render_pass_begin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
-
-	ID screen_format = screen_get_framebuffer_format();
-	{
-		VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * p_draw_list_count);
-		uint32_t command_buffer_count = 0;
-
-		for (uint32_t i = 0; i < p_draw_list_count; i++) {
-			DrawList *dl = _get_draw_list_ptr(p_draw_lists[i]);
-			ERR_CONTINUE_MSG(!dl, "Draw list index (" + itos(i) + ") is not a valid draw list ID.");
-			ERR_CONTINUE_MSG(dl->validation.framebuffer_format != p_format_check,
-					"Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass.");
-
-			if (dl->validation.active) {
-				// Needs to be closed, so close it.
-				vkEndCommandBuffer(dl->command_buffer);
-				dl->validation.active = false;
-			}
-
-			command_buffers[command_buffer_count++] = dl->command_buffer;
-		}
-
-		print_line("to draw: " + itos(command_buffer_count));
-		vkCmdExecuteCommands(p_primary, command_buffer_count, command_buffers);
-	}
-
-	vkCmdEndRenderPass(frame_cmdbuf);
-}
-#endif
-
-void RenderingDeviceVulkan::_free_internal(RID p_id) {
-#ifdef DEV_ENABLED
-	String resource_name;
-	if (resource_names.has(p_id)) {
-		resource_name = resource_names[p_id];
-		resource_names.erase(p_id);
-	}
-#endif
-
-	// Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).
-	if (texture_owner.owns(p_id)) {
-		Texture *texture = texture_owner.get_or_null(p_id);
-		frames[frame].textures_to_dispose_of.push_back(*texture);
-		texture_owner.free(p_id);
-	} else if (framebuffer_owner.owns(p_id)) {
-		Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
-		frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);
-
-		if (framebuffer->invalidated_callback != nullptr) {
-			framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);
-		}
-
-		framebuffer_owner.free(p_id);
-	} else if (sampler_owner.owns(p_id)) {
-		VkSampler *sampler = sampler_owner.get_or_null(p_id);
-		frames[frame].samplers_to_dispose_of.push_back(*sampler);
-		sampler_owner.free(p_id);
-	} else if (vertex_buffer_owner.owns(p_id)) {
-		Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer);
-		vertex_buffer_owner.free(p_id);
-	} else if (vertex_array_owner.owns(p_id)) {
-		vertex_array_owner.free(p_id);
-	} else if (index_buffer_owner.owns(p_id)) {
-		IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);
-		Buffer b;
-		b.allocation = index_buffer->allocation;
-		b.buffer = index_buffer->buffer;
-		b.size = index_buffer->size;
-		b.buffer_info = {};
-		frames[frame].buffers_to_dispose_of.push_back(b);
-		index_buffer_owner.free(p_id);
-	} else if (index_array_owner.owns(p_id)) {
-		index_array_owner.free(p_id);
-	} else if (shader_owner.owns(p_id)) {
-		Shader *shader = shader_owner.get_or_null(p_id);
-		frames[frame].shaders_to_dispose_of.push_back(*shader);
-		shader_owner.free(p_id);
-	} else if (uniform_buffer_owner.owns(p_id)) {
-		Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer);
-		uniform_buffer_owner.free(p_id);
-	} else if (texture_buffer_owner.owns(p_id)) {
-		TextureBuffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(texture_buffer->buffer);
-		frames[frame].buffer_views_to_dispose_of.push_back(texture_buffer->view);
-		texture_buffer_owner.free(p_id);
-	} else if (storage_buffer_owner.owns(p_id)) {
-		Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
-		frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);
-		storage_buffer_owner.free(p_id);
-	} else if (uniform_set_owner.owns(p_id)) {
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
-		frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set);
-		uniform_set_owner.free(p_id);
-
-		if (uniform_set->invalidated_callback != nullptr) {
-			uniform_set->invalidated_callback(uniform_set->invalidated_callback_userdata);
-		}
-	} else if (render_pipeline_owner.owns(p_id)) {
-		RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);
-		frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline);
-		render_pipeline_owner.free(p_id);
-	} else if (compute_pipeline_owner.owns(p_id)) {
-		ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
-		frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);
-		compute_pipeline_owner.free(p_id);
-	} else {
-#ifdef DEV_ENABLED
-		ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);
-#else
-		ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));
-#endif
-	}
-}
-
-void RenderingDeviceVulkan::free(RID p_id) {
-	_THREAD_SAFE_METHOD_
-
-	_free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems.
-	_free_internal(p_id);
-}
-
-// The full list of resources that can be named is in the VkObjectType enum.
-// We just expose the resources that are owned and can be accessed easily.
-void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) {
-	if (texture_owner.owns(p_id)) {
-		Texture *texture = texture_owner.get_or_null(p_id);
-		if (texture->owner.is_null()) {
-			// Don't set the source texture's name when calling on a texture view.
-			context->set_object_name(VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image), p_name);
-		}
-		context->set_object_name(VK_OBJECT_TYPE_IMAGE_VIEW, uint64_t(texture->view), p_name + " View");
-	} else if (framebuffer_owner.owns(p_id)) {
-		//Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
-		// Not implemented for now as the relationship between Framebuffer and RenderPass is very complex.
-	} else if (sampler_owner.owns(p_id)) {
-		VkSampler *sampler = sampler_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_SAMPLER, uint64_t(*sampler), p_name);
-	} else if (vertex_buffer_owner.owns(p_id)) {
-		Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(vertex_buffer->buffer), p_name);
-	} else if (index_buffer_owner.owns(p_id)) {
-		IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(index_buffer->buffer), p_name);
-	} else if (shader_owner.owns(p_id)) {
-		Shader *shader = shader_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(shader->pipeline_layout), p_name + " Pipeline Layout");
-		for (int i = 0; i < shader->sets.size(); i++) {
-			context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, uint64_t(shader->sets[i].descriptor_set_layout), p_name);
-		}
-	} else if (uniform_buffer_owner.owns(p_id)) {
-		Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(uniform_buffer->buffer), p_name);
-	} else if (texture_buffer_owner.owns(p_id)) {
-		TextureBuffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(texture_buffer->buffer.buffer), p_name);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER_VIEW, uint64_t(texture_buffer->view), p_name + " View");
-	} else if (storage_buffer_owner.owns(p_id)) {
-		Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(storage_buffer->buffer), p_name);
-	} else if (uniform_set_owner.owns(p_id)) {
-		UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET, uint64_t(uniform_set->descriptor_set), p_name);
-	} else if (render_pipeline_owner.owns(p_id)) {
-		RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_PIPELINE, uint64_t(pipeline->pipeline), p_name);
-		context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout");
-	} else if (compute_pipeline_owner.owns(p_id)) {
-		ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
-		context->set_object_name(VK_OBJECT_TYPE_PIPELINE, uint64_t(pipeline->pipeline), p_name);
-		context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout");
-	} else {
-		ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));
-		return;
-	}
-#ifdef DEV_ENABLED
-	resource_names[p_id] = p_name;
-#endif
-}
-
-void RenderingDeviceVulkan::draw_command_begin_label(String p_label_name, const Color p_color) {
-	_THREAD_SAFE_METHOD_
-	context->command_begin_label(frames[frame].draw_command_buffer, p_label_name, p_color);
-}
-
-void RenderingDeviceVulkan::draw_command_insert_label(String p_label_name, const Color p_color) {
-	_THREAD_SAFE_METHOD_
-	context->command_insert_label(frames[frame].draw_command_buffer, p_label_name, p_color);
-}
-
-void RenderingDeviceVulkan::draw_command_end_label() {
-	_THREAD_SAFE_METHOD_
-	context->command_end_label(frames[frame].draw_command_buffer);
-}
-
-String RenderingDeviceVulkan::get_device_vendor_name() const {
-	return context->get_device_vendor_name();
-}
-
-String RenderingDeviceVulkan::get_device_name() const {
-	return context->get_device_name();
-}
-
-RenderingDevice::DeviceType RenderingDeviceVulkan::get_device_type() const {
-	return context->get_device_type();
-}
-
-String RenderingDeviceVulkan::get_device_api_version() const {
-	return context->get_device_api_version();
-}
-
-String RenderingDeviceVulkan::get_device_pipeline_cache_uuid() const {
-	return context->get_device_pipeline_cache_uuid();
-}
-
-void RenderingDeviceVulkan::_finalize_command_bufers() {
-	if (draw_list) {
-		ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work).");
-	}
-
-	if (compute_list) {
-		ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
-	}
-
-	{ // Complete the setup buffer (that needs to be processed before anything else).
-		vkEndCommandBuffer(frames[frame].setup_command_buffer);
-		vkEndCommandBuffer(frames[frame].draw_command_buffer);
-	}
-}
-
-void RenderingDeviceVulkan::_begin_frame() {
-	// Erase pending resources.
-	_free_pending_resources(frame);
-
-	// Create setup command buffer and set as the setup buffer.
-
-	{
-		VkCommandBufferBeginInfo cmdbuf_begin;
-		cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-		cmdbuf_begin.pNext = nullptr;
-		cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-		cmdbuf_begin.pInheritanceInfo = nullptr;
-
-		VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0);
-		ERR_FAIL_COND_MSG(err, "vkResetCommandBuffer failed with error " + itos(err) + ".");
-
-		err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-		err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-
-		if (local_device.is_null()) {
-			context->append_command_buffer(frames[frame].draw_command_buffer);
-			context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
-		}
-	}
-
-	// Advance current frame.
-	frames_drawn++;
-	// Advance staging buffer if used.
-	if (staging_buffer_used) {
-		staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
-		staging_buffer_used = false;
-	}
-
-	if (frames[frame].timestamp_count) {
-		vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values.ptr(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
-		vkCmdResetQueryPool(frames[frame].setup_command_buffer, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count);
-		SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
-		SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
-	}
-
-	frames[frame].timestamp_result_count = frames[frame].timestamp_count;
-	frames[frame].timestamp_count = 0;
-	frames[frame].index = Engine::get_singleton()->get_frames_drawn();
-}
-
-VkSampleCountFlagBits RenderingDeviceVulkan::_ensure_supported_sample_count(TextureSamples p_requested_sample_count) const {
-	VkSampleCountFlags sample_count_flags = limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts;
-
-	if (sample_count_flags & rasterization_sample_count[p_requested_sample_count]) {
-		// The requested sample count is supported.
-		return rasterization_sample_count[p_requested_sample_count];
-	} else {
-		// Find the closest lower supported sample count.
-		VkSampleCountFlagBits sample_count = rasterization_sample_count[p_requested_sample_count];
-		while (sample_count > VK_SAMPLE_COUNT_1_BIT) {
-			if (sample_count_flags & sample_count) {
-				return sample_count;
-			}
-			sample_count = (VkSampleCountFlagBits)(sample_count >> 1);
-		}
-	}
-	return VK_SAMPLE_COUNT_1_BIT;
-}
-
-void RenderingDeviceVulkan::swap_buffers() {
-	ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers.");
-	_THREAD_SAFE_METHOD_
-
-	_finalize_command_bufers();
-
-	screen_prepared = false;
-	// Swap buffers.
-	context->swap_buffers();
-
-	frame = (frame + 1) % frame_count;
-
-	_begin_frame();
-}
-
-void RenderingDeviceVulkan::submit() {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
-	ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");
-
-	_finalize_command_bufers();
-
-	VkCommandBuffer command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer };
-	context->local_device_push_command_buffers(local_device, command_buffers, 2);
-	local_device_processing = true;
-}
-
-void RenderingDeviceVulkan::sync() {
-	_THREAD_SAFE_METHOD_
-
-	ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
-	ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");
-
-	context->local_device_sync(local_device);
-	_begin_frame();
-	local_device_processing = false;
-}
-
-VmaPool RenderingDeviceVulkan::_find_or_create_small_allocs_pool(uint32_t p_mem_type_index) {
-	if (small_allocs_pools.has(p_mem_type_index)) {
-		return small_allocs_pools[p_mem_type_index];
-	}
-
-	print_verbose("Creating VMA small objects pool for memory type index " + itos(p_mem_type_index));
-
-	VmaPoolCreateInfo pci;
-	pci.memoryTypeIndex = p_mem_type_index;
-	pci.flags = 0;
-	pci.blockSize = 0;
-	pci.minBlockCount = 0;
-	pci.maxBlockCount = SIZE_MAX;
-	pci.priority = 0.5f;
-	pci.minAllocationAlignment = 0;
-	pci.pMemoryAllocateNext = nullptr;
-	VmaPool pool = VK_NULL_HANDLE;
-	VkResult res = vmaCreatePool(allocator, &pci, &pool);
-	small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time.
-	ERR_FAIL_COND_V_MSG(res, pool, "vmaCreatePool failed with error " + itos(res) + ".");
-
-	return pool;
-}
-
-void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
-	// Free in dependency usage order, so nothing weird happens.
-	// Pipelines.
-	while (frames[p_frame].render_pipelines_to_dispose_of.front()) {
-		RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();
-
-		vkDestroyPipeline(device, pipeline->pipeline, nullptr);
-
-		frames[p_frame].render_pipelines_to_dispose_of.pop_front();
-	}
-
-	while (frames[p_frame].compute_pipelines_to_dispose_of.front()) {
-		ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get();
-
-		vkDestroyPipeline(device, pipeline->pipeline, nullptr);
-
-		frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
-	}
-
-	// Uniform sets.
-	while (frames[p_frame].uniform_sets_to_dispose_of.front()) {
-		UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();
-
-		vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set);
-		_descriptor_pool_free(uniform_set->pool_key, uniform_set->pool);
-
-		frames[p_frame].uniform_sets_to_dispose_of.pop_front();
-	}
-
-	// Buffer views.
-	while (frames[p_frame].buffer_views_to_dispose_of.front()) {
-		VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get();
-
-		vkDestroyBufferView(device, buffer_view, nullptr);
-
-		frames[p_frame].buffer_views_to_dispose_of.pop_front();
-	}
-
-	// Shaders.
-	while (frames[p_frame].shaders_to_dispose_of.front()) {
-		Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();
-
-		// Descriptor set layout for each set.
-		for (int i = 0; i < shader->sets.size(); i++) {
-			vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr);
-		}
-
-		// Pipeline layout.
-		vkDestroyPipelineLayout(device, shader->pipeline_layout, nullptr);
-
-		// Shaders themselves.
-		for (int i = 0; i < shader->pipeline_stages.size(); i++) {
-			vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr);
-		}
-
-		frames[p_frame].shaders_to_dispose_of.pop_front();
-	}
-
-	// Samplers.
-	while (frames[p_frame].samplers_to_dispose_of.front()) {
-		VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
-
-		vkDestroySampler(device, sampler, nullptr);
-
-		frames[p_frame].samplers_to_dispose_of.pop_front();
-	}
-
-	// Framebuffers.
-	while (frames[p_frame].framebuffers_to_dispose_of.front()) {
-		Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();
-
-		for (const KeyValue<Framebuffer::VersionKey, Framebuffer::Version> &E : framebuffer->framebuffers) {
-			// First framebuffer, then render pass because it depends on it.
-			vkDestroyFramebuffer(device, E.value.framebuffer, nullptr);
-			vkDestroyRenderPass(device, E.value.render_pass, nullptr);
-		}
-
-		frames[p_frame].framebuffers_to_dispose_of.pop_front();
-	}
-
-	// Textures.
-	while (frames[p_frame].textures_to_dispose_of.front()) {
-		Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
-
-		if (texture->bound) {
-			WARN_PRINT("Deleted a texture while it was bound.");
-		}
-		vkDestroyImageView(device, texture->view, nullptr);
-		if (texture->owner.is_null()) {
-			// Actually owns the image and the allocation too.
-			image_memory -= texture->allocation_info.size;
-			vmaDestroyImage(allocator, texture->image, texture->allocation);
-		}
-		frames[p_frame].textures_to_dispose_of.pop_front();
-	}
-
-	// Buffers.
-	while (frames[p_frame].buffers_to_dispose_of.front()) {
-		_buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get());
-
-		frames[p_frame].buffers_to_dispose_of.pop_front();
-	}
-}
-
-void RenderingDeviceVulkan::prepare_screen_for_drawing() {
-	_THREAD_SAFE_METHOD_
-	context->prepare_buffers();
-	screen_prepared = true;
-}
-
-uint32_t RenderingDeviceVulkan::get_frame_delay() const {
-	return frame_count;
-}
-
-uint64_t RenderingDeviceVulkan::get_memory_usage(MemoryType p_type) const {
-	if (p_type == MEMORY_BUFFERS) {
-		return buffer_memory;
-	} else if (p_type == MEMORY_TEXTURES) {
-		return image_memory;
-	} else {
-		VmaTotalStatistics stats;
-		vmaCalculateStatistics(allocator, &stats);
-		return stats.total.statistics.allocationBytes;
-	}
-}
-
-void RenderingDeviceVulkan::_flush(bool p_current_frame) {
-	if (local_device.is_valid() && !p_current_frame) {
-		return; // Flushing previous frames has no effect with local device.
-	}
-	// Not doing this crashes RADV (undefined behavior).
-	if (p_current_frame) {
-		vkEndCommandBuffer(frames[frame].setup_command_buffer);
-		vkEndCommandBuffer(frames[frame].draw_command_buffer);
-	}
-
-	if (local_device.is_valid()) {
-		VkCommandBuffer command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer };
-		context->local_device_push_command_buffers(local_device, command_buffers, 2);
-		context->local_device_sync(local_device);
-
-		VkCommandBufferBeginInfo cmdbuf_begin;
-		cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-		cmdbuf_begin.pNext = nullptr;
-		cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-		cmdbuf_begin.pInheritanceInfo = nullptr;
-
-		VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-		err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-
-	} else {
-		context->flush(p_current_frame, p_current_frame);
-		// Re-create the setup command.
-		if (p_current_frame) {
-			VkCommandBufferBeginInfo cmdbuf_begin;
-			cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-			cmdbuf_begin.pNext = nullptr;
-			cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-			cmdbuf_begin.pInheritanceInfo = nullptr;
-
-			VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
-			ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-			context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
-		}
-
-		if (p_current_frame) {
-			VkCommandBufferBeginInfo cmdbuf_begin;
-			cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-			cmdbuf_begin.pNext = nullptr;
-			cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-			cmdbuf_begin.pInheritanceInfo = nullptr;
-
-			VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
-			ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-			context->append_command_buffer(frames[frame].draw_command_buffer);
-		}
-	}
-}
-
-void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
-	// Get our device capabilities.
-	{
-		device_capabilities.version_major = p_context->get_vulkan_major();
-		device_capabilities.version_minor = p_context->get_vulkan_minor();
-	}
-
-	context = p_context;
-	device = p_context->get_device();
-	if (p_local_device) {
-		frame_count = 1;
-		local_device = p_context->local_device_create();
-		device = p_context->local_device_get_vk_device(local_device);
-	} else {
-		frame_count = p_context->get_swapchain_image_count() + 1; // Always need one extra to ensure it's unused at any time, without having to use a fence for this.
-	}
-	limits = p_context->get_device_limits();
-	max_timestamp_query_elements = 256;
-
-	{ // Initialize allocator.
-
-		VmaAllocatorCreateInfo allocatorInfo;
-		memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo));
-		allocatorInfo.physicalDevice = p_context->get_physical_device();
-		allocatorInfo.device = device;
-		allocatorInfo.instance = p_context->get_instance();
-		vmaCreateAllocator(&allocatorInfo, &allocator);
-	}
-
-	frames.resize(frame_count);
-	frame = 0;
-	// Create setup and frame buffers.
-	for (int i = 0; i < frame_count; i++) {
-		frames[i].index = 0;
-
-		{ // Create command pool, one per frame is recommended.
-			VkCommandPoolCreateInfo cmd_pool_info;
-			cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
-			cmd_pool_info.pNext = nullptr;
-			cmd_pool_info.queueFamilyIndex = p_context->get_graphics_queue_family_index();
-			cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-
-			VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &frames[i].command_pool);
-			ERR_FAIL_COND_MSG(res, "vkCreateCommandPool failed with error " + itos(res) + ".");
-		}
-
-		{ // Create command buffers.
-
-			VkCommandBufferAllocateInfo cmdbuf;
-			// No command buffer exists, create it.
-			cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-			cmdbuf.pNext = nullptr;
-			cmdbuf.commandPool = frames[i].command_pool;
-			cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-			cmdbuf.commandBufferCount = 1;
-
-			VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].setup_command_buffer);
-			ERR_CONTINUE_MSG(err, "vkAllocateCommandBuffers failed with error " + itos(err) + ".");
-
-			err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].draw_command_buffer);
-			ERR_CONTINUE_MSG(err, "vkAllocateCommandBuffers failed with error " + itos(err) + ".");
-		}
-
-		{
-			// Create query pool.
-			VkQueryPoolCreateInfo query_pool_create_info;
-			query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
-			query_pool_create_info.flags = 0;
-			query_pool_create_info.pNext = nullptr;
-			query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
-			query_pool_create_info.queryCount = max_timestamp_query_elements;
-			query_pool_create_info.pipelineStatistics = 0;
-
-			vkCreateQueryPool(device, &query_pool_create_info, nullptr, &frames[i].timestamp_pool);
-
-			frames[i].timestamp_names.resize(max_timestamp_query_elements);
-			frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);
-			frames[i].timestamp_count = 0;
-			frames[i].timestamp_result_names.resize(max_timestamp_query_elements);
-			frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);
-			frames[i].timestamp_result_values.resize(max_timestamp_query_elements);
-			frames[i].timestamp_result_count = 0;
-		}
-	}
-
-	{
-		// Begin the first command buffer for the first frame, so
-		// setting up things can be done in the meantime until swap_buffers(), which is called before advance.
-		VkCommandBufferBeginInfo cmdbuf_begin;
-		cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-		cmdbuf_begin.pNext = nullptr;
-		cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-		cmdbuf_begin.pInheritanceInfo = nullptr;
-
-		VkResult err = vkBeginCommandBuffer(frames[0].setup_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-
-		err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin);
-		ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
-		if (local_device.is_null()) {
-			context->set_setup_buffer(frames[0].setup_command_buffer); // Append now so it's added before everything else.
-			context->append_command_buffer(frames[0].draw_command_buffer);
-		}
-	}
-
-	for (int i = 0; i < frame_count; i++) {
-		//Reset all queries in a query pool before doing any operations with them.
-		vkCmdResetQueryPool(frames[0].setup_command_buffer, frames[i].timestamp_pool, 0, max_timestamp_query_elements);
-	}
-
-	staging_buffer_block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");
-	staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
-	staging_buffer_block_size *= 1024; // Kb -> bytes.
-	staging_buffer_max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");
-	staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
-	staging_buffer_max_size *= 1024 * 1024;
-
-	if (staging_buffer_max_size < staging_buffer_block_size * 4) {
-		// Validate enough blocks.
-		staging_buffer_max_size = staging_buffer_block_size * 4;
-	}
-	texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");
-	texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
-
-	frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
-
-	// Ensure current staging block is valid and at least one per frame exists.
-	staging_buffer_current = 0;
-	staging_buffer_used = false;
-
-	for (int i = 0; i < frame_count; i++) {
-		// Staging was never used, create a block.
-		Error err = _insert_staging_block();
-		ERR_CONTINUE(err != OK);
-	}
-
-	max_descriptors_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool");
-
-	// Check to make sure DescriptorPoolKey is good.
-	static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
-
-	draw_list = nullptr;
-	draw_list_count = 0;
-	draw_list_split = false;
-
-	compute_list = nullptr;
-
-	pipelines_cache.file_path = "user://vulkan/pipelines";
-	pipelines_cache.file_path += "." + context->get_device_name().validate_filename().replace(" ", "_").to_lower();
-	if (Engine::get_singleton()->is_editor_hint()) {
-		pipelines_cache.file_path += ".editor";
-	}
-	pipelines_cache.file_path += ".cache";
-
-	// Prepare most fields now.
-	VkPhysicalDeviceProperties props;
-	vkGetPhysicalDeviceProperties(context->get_physical_device(), &props);
-	pipelines_cache.header.magic = 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
-	pipelines_cache.header.device_id = props.deviceID;
-	pipelines_cache.header.vendor_id = props.vendorID;
-	pipelines_cache.header.driver_version = props.driverVersion;
-	memcpy(pipelines_cache.header.uuid, props.pipelineCacheUUID, VK_UUID_SIZE);
-	pipelines_cache.header.driver_abi = sizeof(void *);
-
-	_load_pipeline_cache();
-	print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipelines_cache.buffer.size() / (1024.0f * 1024.0f)));
-	VkPipelineCacheCreateInfo cache_info = {};
-	cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
-	cache_info.pNext = nullptr;
-	if (context->get_pipeline_cache_control_support()) {
-		cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
-	}
-	cache_info.initialDataSize = pipelines_cache.buffer.size();
-	cache_info.pInitialData = pipelines_cache.buffer.ptr();
-	VkResult err = vkCreatePipelineCache(device, &cache_info, nullptr, &pipelines_cache.cache_object);
-
-	if (err != VK_SUCCESS) {
-		WARN_PRINT("vkCreatePipelinecache failed with error " + itos(err) + ".");
-	}
-}
-
-void RenderingDeviceVulkan::_load_pipeline_cache() {
-	DirAccess::make_dir_recursive_absolute(pipelines_cache.file_path.get_base_dir());
-
-	if (FileAccess::exists(pipelines_cache.file_path)) {
-		Error file_error;
-		Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(pipelines_cache.file_path, &file_error);
-		if (file_error != OK || file_data.size() <= (int)sizeof(PipelineCacheHeader)) {
-			WARN_PRINT("Invalid/corrupt pipelines cache.");
-			return;
-		}
-		const PipelineCacheHeader *header = reinterpret_cast<const PipelineCacheHeader *>(file_data.ptr());
-		if (header->magic != 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE) {
-			WARN_PRINT("Invalid pipelines cache magic number.");
-			return;
-		}
-		const uint8_t *loaded_buffer_start = file_data.ptr() + sizeof(PipelineCacheHeader);
-		uint32_t loaded_buffer_size = file_data.size() - sizeof(PipelineCacheHeader);
-		if (header->data_hash != hash_murmur3_buffer(loaded_buffer_start, loaded_buffer_size) ||
-				header->data_size != loaded_buffer_size ||
-				header->vendor_id != pipelines_cache.header.vendor_id ||
-				header->device_id != pipelines_cache.header.device_id ||
-				header->driver_version != pipelines_cache.header.driver_version ||
-				memcmp(header->uuid, pipelines_cache.header.uuid, VK_UUID_SIZE) != 0 ||
-				header->driver_abi != pipelines_cache.header.driver_abi) {
-			WARN_PRINT("Invalid pipelines cache header.");
-			pipelines_cache.current_size = 0;
-			pipelines_cache.buffer.clear();
-		} else {
-			pipelines_cache.current_size = loaded_buffer_size;
-			pipelines_cache.buffer.resize(loaded_buffer_size);
-			memcpy(pipelines_cache.buffer.ptr(), loaded_buffer_start, pipelines_cache.buffer.size());
-		}
-	}
-}
-
-void RenderingDeviceVulkan::_update_pipeline_cache(bool p_closing) {
-	{
-		bool still_saving = pipelines_cache_save_task != WorkerThreadPool::INVALID_TASK_ID && !WorkerThreadPool::get_singleton()->is_task_completed(pipelines_cache_save_task);
-		if (still_saving) {
-			if (p_closing) {
-				WorkerThreadPool::get_singleton()->wait_for_task_completion(pipelines_cache_save_task);
-				pipelines_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;
-			} else {
-				// We can't save until the currently running save is done. We'll retry next time; worst case, we'll save when exiting.
-				return;
-			}
-		}
-	}
-
-	{
-		// FIXME:
-		// We're letting the cache grow unboundedly. We may want to set at limit and see if implementations use LRU or the like.
-		// If we do, we won't be able to assume any longer that the cache is dirty if, and only if, it has grown.
-		size_t pso_blob_size = 0;
-		VkResult vr = vkGetPipelineCacheData(device, pipelines_cache.cache_object, &pso_blob_size, nullptr);
-		ERR_FAIL_COND(vr);
-		size_t difference = pso_blob_size - pipelines_cache.current_size;
-
-		bool must_save = false;
-
-		if (p_closing) {
-			must_save = difference > 0;
-		} else {
-			float save_interval = GLOBAL_GET("rendering/rendering_device/pipeline_cache/save_chunk_size_mb");
-			must_save = difference > 0 && difference / (1024.0f * 1024.0f) >= save_interval;
-		}
-
-		if (must_save) {
-			pipelines_cache.current_size = pso_blob_size;
-		} else {
-			return;
-		}
-	}
-
-	if (p_closing) {
-		_save_pipeline_cache(this);
-	} else {
-		pipelines_cache_save_task = WorkerThreadPool::get_singleton()->add_native_task(&_save_pipeline_cache, this, false, "PipelineCacheSave");
-	}
-}
-
-void RenderingDeviceVulkan::_save_pipeline_cache(void *p_data) {
-	RenderingDeviceVulkan *self = static_cast<RenderingDeviceVulkan *>(p_data);
-
-	self->pipelines_cache.buffer.resize(self->pipelines_cache.current_size);
-
-	self->_thread_safe_.lock();
-	VkResult vr = vkGetPipelineCacheData(self->device, self->pipelines_cache.cache_object, &self->pipelines_cache.current_size, self->pipelines_cache.buffer.ptr());
-	self->_thread_safe_.unlock();
-	ERR_FAIL_COND(vr != VK_SUCCESS && vr != VK_INCOMPLETE); // Incomplete is OK because the cache may have grown since the size was queried (unless when exiting).
-	print_verbose(vformat("Updated PSO cache (%.1f MiB)", self->pipelines_cache.current_size / (1024.0f * 1024.0f)));
-
-	// The real buffer size may now be bigger than the updated current_size.
-	// We take into account the new size but keep the buffer resized in a worst-case fashion.
-
-	self->pipelines_cache.header.data_size = self->pipelines_cache.current_size;
-	self->pipelines_cache.header.data_hash = hash_murmur3_buffer(self->pipelines_cache.buffer.ptr(), self->pipelines_cache.current_size);
-	Ref<FileAccess> f = FileAccess::open(self->pipelines_cache.file_path, FileAccess::WRITE, nullptr);
-	if (f.is_valid()) {
-		f->store_buffer((const uint8_t *)&self->pipelines_cache.header, sizeof(PipelineCacheHeader));
-		f->store_buffer(self->pipelines_cache.buffer.ptr(), self->pipelines_cache.current_size);
-	}
-}
-
-template <class T>
-void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
-	List<RID> owned;
-	p_owner.get_owned_list(&owned);
-	if (owned.size()) {
-		if (owned.size() == 1) {
-			WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
-		} else {
-			WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
-		}
-		for (const RID &E : owned) {
-#ifdef DEV_ENABLED
-			if (resource_names.has(E)) {
-				print_line(String(" - ") + resource_names[E]);
-			}
-#endif
-			free(E);
-		}
-	}
-}
-
-void RenderingDeviceVulkan::capture_timestamp(const String &p_name) {
-	ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
-	ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
-
-	// This should be optional for profiling, else it will slow things down.
-	{
-		VkMemoryBarrier memoryBarrier;
-
-		memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-		memoryBarrier.pNext = nullptr;
-		memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
-				VK_ACCESS_INDEX_READ_BIT |
-				VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
-				VK_ACCESS_UNIFORM_READ_BIT |
-				VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
-				VK_ACCESS_SHADER_READ_BIT |
-				VK_ACCESS_SHADER_WRITE_BIT |
-				VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
-				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-				VK_ACCESS_TRANSFER_READ_BIT |
-				VK_ACCESS_TRANSFER_WRITE_BIT |
-				VK_ACCESS_HOST_READ_BIT |
-				VK_ACCESS_HOST_WRITE_BIT;
-		memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
-				VK_ACCESS_INDEX_READ_BIT |
-				VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
-				VK_ACCESS_UNIFORM_READ_BIT |
-				VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
-				VK_ACCESS_SHADER_READ_BIT |
-				VK_ACCESS_SHADER_WRITE_BIT |
-				VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
-				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-				VK_ACCESS_TRANSFER_READ_BIT |
-				VK_ACCESS_TRANSFER_WRITE_BIT |
-				VK_ACCESS_HOST_READ_BIT |
-				VK_ACCESS_HOST_WRITE_BIT;
-
-		vkCmdPipelineBarrier(frames[frame].draw_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
-	}
-
-	vkCmdWriteTimestamp(frames[frame].draw_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count);
-	frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
-	frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
-	frames[frame].timestamp_count++;
-}
-
-uint64_t RenderingDeviceVulkan::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) {
-	_THREAD_SAFE_METHOD_
-
-	switch (p_resource) {
-		case DRIVER_RESOURCE_VULKAN_DEVICE: {
-			return (uint64_t)context->get_device();
-		} break;
-		case DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE: {
-			return (uint64_t)context->get_physical_device();
-		} break;
-		case DRIVER_RESOURCE_VULKAN_INSTANCE: {
-			return (uint64_t)context->get_instance();
-		} break;
-		case DRIVER_RESOURCE_VULKAN_QUEUE: {
-			return (uint64_t)context->get_graphics_queue();
-		} break;
-		case DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX: {
-			return context->get_graphics_queue_family_index();
-		} break;
-		case DRIVER_RESOURCE_VULKAN_IMAGE: {
-			Texture *tex = texture_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(tex, 0);
-
-			return (uint64_t)tex->image;
-		} break;
-		case DRIVER_RESOURCE_VULKAN_IMAGE_VIEW: {
-			Texture *tex = texture_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(tex, 0);
-
-			return (uint64_t)tex->view;
-		} break;
-		case DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT: {
-			Texture *tex = texture_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(tex, 0);
-
-			return vulkan_formats[tex->format];
-		} break;
-		case DRIVER_RESOURCE_VULKAN_SAMPLER: {
-			VkSampler *sampler = sampler_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(sampler, 0);
-
-			return uint64_t(*sampler);
-		} break;
-		case DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET: {
-			UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(uniform_set, 0);
-
-			return uint64_t(uniform_set->descriptor_set);
-		} break;
-		case DRIVER_RESOURCE_VULKAN_BUFFER: {
-			Buffer *buffer = nullptr;
-			if (vertex_buffer_owner.owns(p_rid)) {
-				buffer = vertex_buffer_owner.get_or_null(p_rid);
-			} else if (index_buffer_owner.owns(p_rid)) {
-				buffer = index_buffer_owner.get_or_null(p_rid);
-			} else if (uniform_buffer_owner.owns(p_rid)) {
-				buffer = uniform_buffer_owner.get_or_null(p_rid);
-			} else if (texture_buffer_owner.owns(p_rid)) {
-				buffer = &texture_buffer_owner.get_or_null(p_rid)->buffer;
-			} else if (storage_buffer_owner.owns(p_rid)) {
-				buffer = storage_buffer_owner.get_or_null(p_rid);
-			}
-
-			ERR_FAIL_NULL_V(buffer, 0);
-
-			return uint64_t(buffer->buffer);
-		} break;
-		case DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE: {
-			ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(compute_pipeline, 0);
-
-			return uint64_t(compute_pipeline->pipeline);
-		} break;
-		case DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE: {
-			RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);
-			ERR_FAIL_NULL_V(render_pipeline, 0);
-
-			return uint64_t(render_pipeline->pipeline);
-		} break;
-		default: {
-			// Not supported for this driver.
-			return 0;
-		} break;
-	}
-}
-
-uint32_t RenderingDeviceVulkan::get_captured_timestamps_count() const {
-	return frames[frame].timestamp_result_count;
-}
-
-uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const {
-	return frames[frame].index;
-}
-
-static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
-	uint64_t u1 = (u & 0xffffffff);
-	uint64_t v1 = (v & 0xffffffff);
-	uint64_t t = (u1 * v1);
-	uint64_t w3 = (t & 0xffffffff);
-	uint64_t k = (t >> 32);
-
-	u >>= 32;
-	t = (u * v1) + k;
-	k = (t & 0xffffffff);
-	uint64_t w1 = (t >> 32);
-
-	v >>= 32;
-	t = (u1 * v) + k;
-	k = (t >> 32);
-
-	h = (u * v) + w1 + k;
-	l = (t << 32) + w3;
-}
-
-uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
-
-	// This sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
-	// So, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible.
-	// Need to do 128 bits fixed point multiplication to get the right value.
-
-	uint64_t shift_bits = 16;
-
-	uint64_t h, l;
-
-	mult64to128(frames[frame].timestamp_result_values[p_index], uint64_t(double(limits.timestampPeriod) * double(1 << shift_bits)), h, l);
-	l >>= shift_bits;
-	l |= h << (64 - shift_bits);
-
-	return l;
-}
-
-uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
-	return frames[frame].timestamp_cpu_result_values[p_index];
-}
-
-String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) const {
-	ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
-	return frames[frame].timestamp_result_names[p_index];
-}
-
-uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
-	switch (p_limit) {
-		case LIMIT_MAX_BOUND_UNIFORM_SETS:
-			return limits.maxBoundDescriptorSets;
-		case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS:
-			return limits.maxColorAttachments;
-		case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET:
-			return limits.maxDescriptorSetSampledImages;
-		case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET:
-			return limits.maxDescriptorSetSamplers;
-		case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET:
-			return limits.maxDescriptorSetStorageBuffers;
-		case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET:
-			return limits.maxDescriptorSetStorageImages;
-		case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET:
-			return limits.maxDescriptorSetUniformBuffers;
-		case LIMIT_MAX_DRAW_INDEXED_INDEX:
-			return limits.maxDrawIndexedIndexValue;
-		case LIMIT_MAX_FRAMEBUFFER_HEIGHT:
-			return limits.maxFramebufferHeight;
-		case LIMIT_MAX_FRAMEBUFFER_WIDTH:
-			return limits.maxFramebufferWidth;
-		case LIMIT_MAX_TEXTURE_ARRAY_LAYERS:
-			return limits.maxImageArrayLayers;
-		case LIMIT_MAX_TEXTURE_SIZE_1D:
-			return limits.maxImageDimension1D;
-		case LIMIT_MAX_TEXTURE_SIZE_2D:
-			return limits.maxImageDimension2D;
-		case LIMIT_MAX_TEXTURE_SIZE_3D:
-			return limits.maxImageDimension3D;
-		case LIMIT_MAX_TEXTURE_SIZE_CUBE:
-			return limits.maxImageDimensionCube;
-		case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:
-			return limits.maxPerStageDescriptorSampledImages;
-		case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE:
-			return limits.maxPerStageDescriptorSamplers;
-		case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE:
-			return limits.maxPerStageDescriptorStorageBuffers;
-		case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE:
-			return limits.maxPerStageDescriptorStorageImages;
-		case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE:
-			return limits.maxPerStageDescriptorUniformBuffers;
-		case LIMIT_MAX_PUSH_CONSTANT_SIZE:
-			return limits.maxPushConstantsSize;
-		case LIMIT_MAX_UNIFORM_BUFFER_SIZE:
-			return limits.maxUniformBufferRange;
-		case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET:
-			return limits.maxVertexInputAttributeOffset;
-		case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES:
-			return limits.maxVertexInputAttributes;
-		case LIMIT_MAX_VERTEX_INPUT_BINDINGS:
-			return limits.maxVertexInputBindings;
-		case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE:
-			return limits.maxVertexInputBindingStride;
-		case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
-			return limits.minUniformBufferOffsetAlignment;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:
-			return limits.maxComputeWorkGroupCount[0];
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:
-			return limits.maxComputeWorkGroupCount[1];
-		case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:
-			return limits.maxComputeWorkGroupCount[2];
-		case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS:
-			return limits.maxComputeWorkGroupInvocations;
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:
-			return limits.maxComputeWorkGroupSize[0];
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:
-			return limits.maxComputeWorkGroupSize[1];
-		case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
-			return limits.maxComputeWorkGroupSize[2];
-		case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
-			return limits.maxViewportDimensions[0];
-		case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
-			return limits.maxViewportDimensions[1];
-		case LIMIT_SUBGROUP_SIZE: {
-			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.size;
-		}
-		case LIMIT_SUBGROUP_MIN_SIZE: {
-			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.min_size;
-		}
-		case LIMIT_SUBGROUP_MAX_SIZE: {
-			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.max_size;
-		}
-		case LIMIT_SUBGROUP_IN_SHADERS: {
-			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.supported_stages_flags_rd();
-		}
-		case LIMIT_SUBGROUP_OPERATIONS: {
-			VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
-			return subgroup_capabilities.supported_operations_flags_rd();
-		}
-		case LIMIT_VRS_TEXEL_WIDTH: {
-			return context->get_vrs_capabilities().texel_size.x;
-		}
-		case LIMIT_VRS_TEXEL_HEIGHT: {
-			return context->get_vrs_capabilities().texel_size.y;
-		}
-		default:
-			ERR_FAIL_V(0);
-	}
-
-	return 0;
-}
-
-void RenderingDeviceVulkan::finalize() {
-	// Free all resources.
-
-	_flush(false);
-
-	_free_rids(render_pipeline_owner, "Pipeline");
-	_free_rids(compute_pipeline_owner, "Compute");
-	_free_rids(uniform_set_owner, "UniformSet");
-	_free_rids(texture_buffer_owner, "TextureBuffer");
-	_free_rids(storage_buffer_owner, "StorageBuffer");
-	_free_rids(uniform_buffer_owner, "UniformBuffer");
-	_free_rids(shader_owner, "Shader");
-	_free_rids(index_array_owner, "IndexArray");
-	_free_rids(index_buffer_owner, "IndexBuffer");
-	_free_rids(vertex_array_owner, "VertexArray");
-	_free_rids(vertex_buffer_owner, "VertexBuffer");
-	_free_rids(framebuffer_owner, "Framebuffer");
-	_free_rids(sampler_owner, "Sampler");
-	{
-		// For textures it's a bit more difficult because they may be shared.
-		List<RID> owned;
-		texture_owner.get_owned_list(&owned);
-		if (owned.size()) {
-			if (owned.size() == 1) {
-				WARN_PRINT("1 RID of type \"Texture\" was leaked.");
-			} else {
-				WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
-			}
-			// Free shared first.
-			for (List<RID>::Element *E = owned.front(); E;) {
-				List<RID>::Element *N = E->next();
-				if (texture_is_shared(E->get())) {
-#ifdef DEV_ENABLED
-					if (resource_names.has(E->get())) {
-						print_line(String(" - ") + resource_names[E->get()]);
-					}
-#endif
-					free(E->get());
-					owned.erase(E);
-				}
-				E = N;
-			}
-			// Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
-			for (const RID &E : owned) {
-#ifdef DEV_ENABLED
-				if (resource_names.has(E)) {
-					print_line(String(" - ") + resource_names[E]);
-				}
-#endif
-				free(E);
-			}
-		}
-	}
-
-	// Free everything pending.
-	for (int i = 0; i < frame_count; i++) {
-		int f = (frame + i) % frame_count;
-		_free_pending_resources(f);
-		vkDestroyCommandPool(device, frames[i].command_pool, nullptr);
-		vkDestroyQueryPool(device, frames[i].timestamp_pool, nullptr);
-	}
-	_update_pipeline_cache(true);
-
-	vkDestroyPipelineCache(device, pipelines_cache.cache_object, nullptr);
-
-	for (int i = 0; i < split_draw_list_allocators.size(); i++) {
-		vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, nullptr);
-	}
-
-	frames.clear();
-
-	for (int i = 0; i < staging_buffer_blocks.size(); i++) {
-		vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation);
-	}
-	while (small_allocs_pools.size()) {
-		HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin();
-		vmaDestroyPool(allocator, E->value);
-		small_allocs_pools.remove(E);
-	}
-	vmaDestroyAllocator(allocator);
-
-	while (vertex_formats.size()) {
-		HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin();
-		memdelete_arr(temp->value.bindings);
-		memdelete_arr(temp->value.attributes);
-		vertex_formats.remove(temp);
-	}
-
-	for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) {
-		vkDestroyRenderPass(device, E.value.render_pass, nullptr);
-	}
-	framebuffer_formats.clear();
-
-	// All these should be clear at this point.
-	ERR_FAIL_COND(descriptor_pools.size());
-	ERR_FAIL_COND(dependency_map.size());
-	ERR_FAIL_COND(reverse_dependency_map.size());
-}
-
-RenderingDevice *RenderingDeviceVulkan::create_local_device() {
-	RenderingDeviceVulkan *rd = memnew(RenderingDeviceVulkan);
-	rd->initialize(context, true);
-	return rd;
-}
-
-bool RenderingDeviceVulkan::has_feature(const Features p_feature) const {
-	switch (p_feature) {
-		case SUPPORTS_MULTIVIEW: {
-			VulkanContext::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities();
-			return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
-		} break;
-		case SUPPORTS_FSR_HALF_FLOAT: {
-			return context->get_shader_capabilities().shader_float16_is_supported && context->get_physical_device_features().shaderInt16 && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
-		} break;
-		case SUPPORTS_ATTACHMENT_VRS: {
-			VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
-			return vrs_capabilities.attachment_vrs_supported && context->get_physical_device_features().shaderStorageImageExtendedFormats;
-		} break;
-		case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: {
-			return true;
-		} break;
-		default: {
-			return false;
-		}
-	}
-}
-
-RenderingDeviceVulkan::RenderingDeviceVulkan() {
-	device_capabilities.device_family = DEVICE_VULKAN;
-}
-
-RenderingDeviceVulkan::~RenderingDeviceVulkan() {
-	if (local_device.is_valid()) {
-		finalize();
-		context->local_device_free(local_device);
-	}
-}

+ 0 - 1293
drivers/vulkan/rendering_device_vulkan.h

@@ -1,1293 +0,0 @@
-/**************************************************************************/
-/*  rendering_device_vulkan.h                                             */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#ifndef RENDERING_DEVICE_VULKAN_H
-#define RENDERING_DEVICE_VULKAN_H
-
-#include "core/object/worker_thread_pool.h"
-#include "core/os/thread_safe.h"
-#include "core/templates/local_vector.h"
-#include "core/templates/oa_hash_map.h"
-#include "core/templates/rid_owner.h"
-#include "servers/rendering/rendering_device.h"
-
-#ifdef DEBUG_ENABLED
-#ifndef _DEBUG
-#define _DEBUG
-#endif
-#endif
-#include "thirdparty/vulkan/vk_mem_alloc.h"
-
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
-
-class VulkanContext;
-
-class RenderingDeviceVulkan : public RenderingDevice {
-	_THREAD_SAFE_CLASS_
-
-	// Miscellaneous tables that map
-	// our enums to enums used
-	// by vulkan.
-
-	VkPhysicalDeviceLimits limits;
-	static const VkFormat vulkan_formats[DATA_FORMAT_MAX];
-	static const char *named_formats[DATA_FORMAT_MAX];
-	static const VkCompareOp compare_operators[COMPARE_OP_MAX];
-	static const VkStencilOp stencil_operations[STENCIL_OP_MAX];
-	static const VkSampleCountFlagBits rasterization_sample_count[TEXTURE_SAMPLES_MAX];
-	static const VkLogicOp logic_operations[RenderingDevice::LOGIC_OP_MAX];
-	static const VkBlendFactor blend_factors[RenderingDevice::BLEND_FACTOR_MAX];
-	static const VkBlendOp blend_operations[RenderingDevice::BLEND_OP_MAX];
-	static const VkSamplerAddressMode address_modes[SAMPLER_REPEAT_MODE_MAX];
-	static const VkBorderColor sampler_border_colors[SAMPLER_BORDER_COLOR_MAX];
-	static const VkImageType vulkan_image_type[TEXTURE_TYPE_MAX];
-
-	// Functions used for format
-	// validation, and ensures the
-	// user passes valid data.
-
-	static int get_format_vertex_size(DataFormat p_format);
-	static uint32_t get_image_format_pixel_size(DataFormat p_format);
-	static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
-	uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
-	static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
-	static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr);
-	static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
-	static bool format_has_stencil(DataFormat p_format);
-
-	/***************************/
-	/**** ID INFRASTRUCTURE ****/
-	/***************************/
-
-	enum IDType {
-		ID_TYPE_FRAMEBUFFER_FORMAT,
-		ID_TYPE_VERTEX_FORMAT,
-		ID_TYPE_DRAW_LIST,
-		ID_TYPE_SPLIT_DRAW_LIST,
-		ID_TYPE_COMPUTE_LIST,
-		ID_TYPE_MAX,
-		ID_BASE_SHIFT = 58 // 5 bits for ID types.
-	};
-
-	VkDevice device = VK_NULL_HANDLE;
-
-	HashMap<RID, HashSet<RID>> dependency_map; // IDs to IDs that depend on it.
-	HashMap<RID, HashSet<RID>> reverse_dependency_map; // Same as above, but in reverse.
-
-	void _add_dependency(RID p_id, RID p_depends_on);
-	void _free_dependencies(RID p_id);
-
-	/*****************/
-	/**** TEXTURE ****/
-	/*****************/
-
-	// In Vulkan, the concept of textures does not exist,
-	// instead there is the image (the memory pretty much,
-	// the view (how the memory is interpreted) and the
-	// sampler (how it's sampled from the shader).
-	//
-	// Texture here includes the first two stages, but
-	// It's possible to create textures sharing the image
-	// but with different views. The main use case for this
-	// is textures that can be read as both SRGB/Linear,
-	// or slices of a texture (a mipmap, a layer, a 3D slice)
-	// for a framebuffer to render into it.
-
-	struct Texture {
-		VkImage image = VK_NULL_HANDLE;
-		VmaAllocation allocation = nullptr;
-		VmaAllocationInfo allocation_info;
-		VkImageView view = VK_NULL_HANDLE;
-
-		TextureType type;
-		DataFormat format;
-		TextureSamples samples;
-		uint32_t width = 0;
-		uint32_t height = 0;
-		uint32_t depth = 0;
-		uint32_t layers = 0;
-		uint32_t mipmaps = 0;
-		uint32_t usage_flags = 0;
-		uint32_t base_mipmap = 0;
-		uint32_t base_layer = 0;
-
-		Vector<DataFormat> allowed_shared_formats;
-
-		VkImageLayout layout;
-
-		uint64_t used_in_frame = 0;
-		bool used_in_transfer = false;
-		bool used_in_raster = false;
-		bool used_in_compute = false;
-
-		bool is_resolve_buffer = false;
-
-		uint32_t read_aspect_mask = 0;
-		uint32_t barrier_aspect_mask = 0;
-		bool bound = false; // Bound to framebffer.
-		RID owner;
-	};
-
-	RID_Owner<Texture> texture_owner;
-	uint32_t texture_upload_region_size_px = 0;
-
-	Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false);
-	Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue);
-
-	/*****************/
-	/**** SAMPLER ****/
-	/*****************/
-
-	RID_Owner<VkSampler> sampler_owner;
-
-	/***************************/
-	/**** BUFFER MANAGEMENT ****/
-	/***************************/
-
-	// These are temporary buffers on CPU memory that hold
-	// the information until the CPU fetches it and places it
-	// either on GPU buffers, or images (textures). It ensures
-	// updates are properly synchronized with whatever the
-	// GPU is doing.
-	//
-	// The logic here is as follows, only 3 of these
-	// blocks are created at the beginning (one per frame)
-	// they can each belong to a frame (assigned to current when
-	// used) and they can only be reused after the same frame is
-	// recycled.
-	//
-	// When CPU requires to allocate more than what is available,
-	// more of these buffers are created. If a limit is reached,
-	// then a fence will ensure will wait for blocks allocated
-	// in previous frames are processed. If that fails, then
-	// another fence will ensure everything pending for the current
-	// frame is processed (effectively stalling).
-	//
-	// See the comments in the code to understand better how it works.
-
-	struct StagingBufferBlock {
-		VkBuffer buffer = VK_NULL_HANDLE;
-		VmaAllocation allocation = nullptr;
-		uint64_t frame_used = 0;
-		uint32_t fill_amount = 0;
-	};
-
-	Vector<StagingBufferBlock> staging_buffer_blocks;
-	int staging_buffer_current = 0;
-	uint32_t staging_buffer_block_size = 0;
-	uint64_t staging_buffer_max_size = 0;
-	bool staging_buffer_used = false;
-
-	Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true);
-	Error _insert_staging_block();
-
-	struct Buffer {
-		uint32_t size = 0;
-		uint32_t usage = 0;
-		VkBuffer buffer = VK_NULL_HANDLE;
-		VmaAllocation allocation = nullptr;
-		VkDescriptorBufferInfo buffer_info; // Used for binding.
-		Buffer() {
-		}
-	};
-
-	Error _buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mem_usage, VmaAllocationCreateFlags p_mem_flags);
-	Error _buffer_free(Buffer *p_buffer);
-	Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32);
-
-	void _full_barrier(bool p_sync_with_draw);
-	void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw);
-	void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw);
-
-	/*********************/
-	/**** FRAMEBUFFER ****/
-	/*********************/
-
-	// In Vulkan, framebuffers work similar to how they
-	// do in OpenGL, with the exception that
-	// the "format" (vkRenderPass) is not dynamic
-	// and must be more or less the same as the one
-	// used for the render pipelines.
-
-	struct FramebufferFormatKey {
-		Vector<AttachmentFormat> attachments;
-		Vector<FramebufferPass> passes;
-		uint32_t view_count = 1;
-
-		bool operator<(const FramebufferFormatKey &p_key) const {
-			if (view_count != p_key.view_count) {
-				return view_count < p_key.view_count;
-			}
-
-			uint32_t pass_size = passes.size();
-			uint32_t key_pass_size = p_key.passes.size();
-			if (pass_size != key_pass_size) {
-				return pass_size < key_pass_size;
-			}
-			const FramebufferPass *pass_ptr = passes.ptr();
-			const FramebufferPass *key_pass_ptr = p_key.passes.ptr();
-
-			for (uint32_t i = 0; i < pass_size; i++) {
-				{ // Compare color attachments.
-					uint32_t attachment_size = pass_ptr[i].color_attachments.size();
-					uint32_t key_attachment_size = key_pass_ptr[i].color_attachments.size();
-					if (attachment_size != key_attachment_size) {
-						return attachment_size < key_attachment_size;
-					}
-					const int32_t *pass_attachment_ptr = pass_ptr[i].color_attachments.ptr();
-					const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].color_attachments.ptr();
-
-					for (uint32_t j = 0; j < attachment_size; j++) {
-						if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
-							return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
-						}
-					}
-				}
-				{ // Compare input attachments.
-					uint32_t attachment_size = pass_ptr[i].input_attachments.size();
-					uint32_t key_attachment_size = key_pass_ptr[i].input_attachments.size();
-					if (attachment_size != key_attachment_size) {
-						return attachment_size < key_attachment_size;
-					}
-					const int32_t *pass_attachment_ptr = pass_ptr[i].input_attachments.ptr();
-					const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].input_attachments.ptr();
-
-					for (uint32_t j = 0; j < attachment_size; j++) {
-						if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
-							return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
-						}
-					}
-				}
-				{ // Compare resolve attachments.
-					uint32_t attachment_size = pass_ptr[i].resolve_attachments.size();
-					uint32_t key_attachment_size = key_pass_ptr[i].resolve_attachments.size();
-					if (attachment_size != key_attachment_size) {
-						return attachment_size < key_attachment_size;
-					}
-					const int32_t *pass_attachment_ptr = pass_ptr[i].resolve_attachments.ptr();
-					const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].resolve_attachments.ptr();
-
-					for (uint32_t j = 0; j < attachment_size; j++) {
-						if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
-							return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
-						}
-					}
-				}
-				{ // Compare preserve attachments.
-					uint32_t attachment_size = pass_ptr[i].preserve_attachments.size();
-					uint32_t key_attachment_size = key_pass_ptr[i].preserve_attachments.size();
-					if (attachment_size != key_attachment_size) {
-						return attachment_size < key_attachment_size;
-					}
-					const int32_t *pass_attachment_ptr = pass_ptr[i].preserve_attachments.ptr();
-					const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].preserve_attachments.ptr();
-
-					for (uint32_t j = 0; j < attachment_size; j++) {
-						if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
-							return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
-						}
-					}
-				}
-				if (pass_ptr[i].depth_attachment != key_pass_ptr[i].depth_attachment) {
-					return pass_ptr[i].depth_attachment < key_pass_ptr[i].depth_attachment;
-				}
-			}
-
-			int as = attachments.size();
-			int bs = p_key.attachments.size();
-			if (as != bs) {
-				return as < bs;
-			}
-
-			const AttachmentFormat *af_a = attachments.ptr();
-			const AttachmentFormat *af_b = p_key.attachments.ptr();
-			for (int i = 0; i < as; i++) {
-				const AttachmentFormat &a = af_a[i];
-				const AttachmentFormat &b = af_b[i];
-				if (a.format != b.format) {
-					return a.format < b.format;
-				}
-				if (a.samples != b.samples) {
-					return a.samples < b.samples;
-				}
-				if (a.usage_flags != b.usage_flags) {
-					return a.usage_flags < b.usage_flags;
-				}
-			}
-
-			return false; // Equal.
-		}
-	};
-
-	VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count = 1, Vector<TextureSamples> *r_samples = nullptr);
-	// This is a cache and it's never freed, it ensures
-	// IDs for a given format are always unique.
-	RBMap<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache;
-	struct FramebufferFormat {
-		const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E;
-		VkRenderPass render_pass = VK_NULL_HANDLE; // Here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec).
-		Vector<TextureSamples> pass_samples;
-		uint32_t view_count = 1; // Number of views.
-	};
-
-	HashMap<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
-
-	struct Framebuffer {
-		FramebufferFormatID format_id = 0;
-		struct VersionKey {
-			InitialAction initial_color_action;
-			FinalAction final_color_action;
-			InitialAction initial_depth_action;
-			FinalAction final_depth_action;
-			uint32_t view_count;
-
-			bool operator<(const VersionKey &p_key) const {
-				if (initial_color_action == p_key.initial_color_action) {
-					if (final_color_action == p_key.final_color_action) {
-						if (initial_depth_action == p_key.initial_depth_action) {
-							if (final_depth_action == p_key.final_depth_action) {
-								return view_count < p_key.view_count;
-							} else {
-								return final_depth_action < p_key.final_depth_action;
-							}
-						} else {
-							return initial_depth_action < p_key.initial_depth_action;
-						}
-					} else {
-						return final_color_action < p_key.final_color_action;
-					}
-				} else {
-					return initial_color_action < p_key.initial_color_action;
-				}
-			}
-		};
-
-		uint32_t storage_mask = 0;
-		Vector<RID> texture_ids;
-		InvalidationCallback invalidated_callback = nullptr;
-		void *invalidated_callback_userdata = nullptr;
-
-		struct Version {
-			VkFramebuffer framebuffer = VK_NULL_HANDLE;
-			VkRenderPass render_pass = VK_NULL_HANDLE; // This one is owned.
-			uint32_t subpass_count = 1;
-		};
-
-		RBMap<VersionKey, Version> framebuffers;
-		Size2 size;
-		uint32_t view_count;
-	};
-
-	RID_Owner<Framebuffer> framebuffer_owner;
-
-	/***********************/
-	/**** VERTEX BUFFER ****/
-	/***********************/
-
-	// Vertex buffers in Vulkan are similar to how
-	// they work in OpenGL, except that instead of
-	// an attribute index, there is a buffer binding
-	// index (for binding the buffers in real-time)
-	// and a location index (what is used in the shader).
-	//
-	// This mapping is done here internally, and it's not
-	// exposed.
-
-	RID_Owner<Buffer> vertex_buffer_owner;
-
-	struct VertexDescriptionKey {
-		Vector<VertexAttribute> vertex_formats;
-		bool operator==(const VertexDescriptionKey &p_key) const {
-			int vdc = vertex_formats.size();
-			int vdck = p_key.vertex_formats.size();
-
-			if (vdc != vdck) {
-				return false;
-			} else {
-				const VertexAttribute *a_ptr = vertex_formats.ptr();
-				const VertexAttribute *b_ptr = p_key.vertex_formats.ptr();
-				for (int i = 0; i < vdc; i++) {
-					const VertexAttribute &a = a_ptr[i];
-					const VertexAttribute &b = b_ptr[i];
-
-					if (a.location != b.location) {
-						return false;
-					}
-					if (a.offset != b.offset) {
-						return false;
-					}
-					if (a.format != b.format) {
-						return false;
-					}
-					if (a.stride != b.stride) {
-						return false;
-					}
-					if (a.frequency != b.frequency) {
-						return false;
-					}
-				}
-				return true; // They are equal.
-			}
-		}
-
-		uint32_t hash() const {
-			int vdc = vertex_formats.size();
-			uint32_t h = hash_murmur3_one_32(vdc);
-			const VertexAttribute *ptr = vertex_formats.ptr();
-			for (int i = 0; i < vdc; i++) {
-				const VertexAttribute &vd = ptr[i];
-				h = hash_murmur3_one_32(vd.location, h);
-				h = hash_murmur3_one_32(vd.offset, h);
-				h = hash_murmur3_one_32(vd.format, h);
-				h = hash_murmur3_one_32(vd.stride, h);
-				h = hash_murmur3_one_32(vd.frequency, h);
-			}
-			return hash_fmix32(h);
-		}
-	};
-
-	struct VertexDescriptionHash {
-		static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) {
-			return p_key.hash();
-		}
-	};
-
-	// This is a cache and it's never freed, it ensures that
-	// ID used for a specific format always remain the same.
-	HashMap<VertexDescriptionKey, VertexFormatID, VertexDescriptionHash> vertex_format_cache;
-
-	struct VertexDescriptionCache {
-		Vector<VertexAttribute> vertex_formats;
-		VkVertexInputBindingDescription *bindings = nullptr;
-		VkVertexInputAttributeDescription *attributes = nullptr;
-		VkPipelineVertexInputStateCreateInfo create_info;
-	};
-
-	HashMap<VertexFormatID, VertexDescriptionCache> vertex_formats;
-
-	struct VertexArray {
-		RID buffer;
-		VertexFormatID description = 0;
-		int vertex_count = 0;
-		uint32_t max_instances_allowed = 0;
-
-		Vector<VkBuffer> buffers; // Not owned, just referenced.
-		Vector<VkDeviceSize> offsets;
-	};
-
-	RID_Owner<VertexArray> vertex_array_owner;
-
-	struct IndexBuffer : public Buffer {
-		uint32_t max_index = 0; // Used for validation.
-		uint32_t index_count = 0;
-		VkIndexType index_type = VK_INDEX_TYPE_NONE_NV;
-		bool supports_restart_indices = false;
-	};
-
-	RID_Owner<IndexBuffer> index_buffer_owner;
-
-	struct IndexArray {
-		uint32_t max_index = 0; // Remember the maximum index here too, for validation.
-		VkBuffer buffer; // Not owned, inherited from index buffer.
-		uint32_t offset = 0;
-		uint32_t indices = 0;
-		VkIndexType index_type = VK_INDEX_TYPE_NONE_NV;
-		bool supports_restart_indices = false;
-	};
-
-	RID_Owner<IndexArray> index_array_owner;
-
-	/****************/
-	/**** SHADER ****/
-	/****************/
-
-	// Vulkan specifies a really complex behavior for the application
-	// in order to tell when descriptor sets need to be re-bound (or not).
-	// "When binding a descriptor set (see Descriptor Set Binding) to set
-	//  number N, if the previously bound descriptor sets for sets zero
-	//  through N-1 were all bound using compatible pipeline layouts,
-	//  then performing this binding does not disturb any of the lower numbered sets.
-	//  If, additionally, the previous bound descriptor set for set N was
-	//  bound using a pipeline layout compatible for set N, then the bindings
-	//  in sets numbered greater than N are also not disturbed."
-	// As a result, we need to figure out quickly when something is no longer "compatible".
-	// in order to avoid costly rebinds.
-
-	struct UniformInfo {
-		UniformType type = UniformType::UNIFORM_TYPE_MAX;
-		bool writable = false;
-		int binding = 0;
-		uint32_t stages = 0;
-		int length = 0; // Size of arrays (in total elements), or ubos (in bytes * total elements).
-
-		bool operator!=(const UniformInfo &p_info) const {
-			return (binding != p_info.binding || type != p_info.type || writable != p_info.writable || stages != p_info.stages || length != p_info.length);
-		}
-
-		bool operator<(const UniformInfo &p_info) const {
-			if (binding != p_info.binding) {
-				return binding < p_info.binding;
-			}
-			if (type != p_info.type) {
-				return type < p_info.type;
-			}
-			if (writable != p_info.writable) {
-				return writable < p_info.writable;
-			}
-			if (stages != p_info.stages) {
-				return stages < p_info.stages;
-			}
-			return length < p_info.length;
-		}
-	};
-
-	struct UniformSetFormat {
-		Vector<UniformInfo> uniform_info;
-		bool operator<(const UniformSetFormat &p_format) const {
-			uint32_t size = uniform_info.size();
-			uint32_t psize = p_format.uniform_info.size();
-
-			if (size != psize) {
-				return size < psize;
-			}
-
-			const UniformInfo *infoptr = uniform_info.ptr();
-			const UniformInfo *pinfoptr = p_format.uniform_info.ptr();
-
-			for (uint32_t i = 0; i < size; i++) {
-				if (infoptr[i] != pinfoptr[i]) {
-					return infoptr[i] < pinfoptr[i];
-				}
-			}
-
-			return false;
-		}
-	};
-
-	// Always grows, never shrinks, ensuring unique IDs, but we assume
-	// the amount of formats will never be a problem, as the amount of shaders
-	// in a game is limited.
-	RBMap<UniformSetFormat, uint32_t> uniform_set_format_cache;
-
-	// Shaders in Vulkan are just pretty much
-	// precompiled blocks of SPIR-V bytecode. They
-	// are most likely not really compiled to host
-	// assembly until a pipeline is created.
-	//
-	// When supplying the shaders, this implementation
-	// will use the reflection abilities of glslang to
-	// understand and cache everything required to
-	// create and use the descriptor sets (Vulkan's
-	// biggest pain).
-	//
-	// Additionally, hashes are created for every set
-	// to do quick validation and ensuring the user
-	// does not submit something invalid.
-
-	struct Shader {
-		struct Set {
-			Vector<UniformInfo> uniform_info;
-			VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE;
-		};
-
-		uint64_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
-		uint32_t fragment_output_mask = 0;
-
-		struct PushConstant {
-			uint32_t size = 0;
-			uint32_t vk_stages_mask = 0;
-		};
-
-		PushConstant push_constant;
-
-		uint32_t compute_local_size[3] = { 0, 0, 0 };
-
-		struct SpecializationConstant {
-			PipelineSpecializationConstant constant;
-			uint32_t stage_flags = 0;
-		};
-
-		bool is_compute = false;
-		Vector<Set> sets;
-		Vector<uint32_t> set_formats;
-		Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
-		Vector<SpecializationConstant> specialization_constants;
-		VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
-		String name; // Used for debug.
-	};
-
-	String _shader_uniform_debug(RID p_shader, int p_set = -1);
-
-	RID_Owner<Shader> shader_owner;
-
-	/******************/
-	/**** UNIFORMS ****/
-	/******************/
-
-	// Descriptor sets require allocation from a pool.
-	// The documentation on how to use pools properly
-	// is scarce, and the documentation is strange.
-	//
-	// Basically, you can mix and match pools as you
-	// like, but you'll run into fragmentation issues.
-	// Because of this, the recommended approach is to
-	// create a pool for every descriptor set type, as
-	// this prevents fragmentation.
-	//
-	// This is implemented here as a having a list of
-	// pools (each can contain up to 64 sets) for each
-	// set layout. The amount of sets for each type
-	// is used as the key.
-
-	enum {
-		MAX_DESCRIPTOR_POOL_ELEMENT = 65535
-	};
-
-	struct DescriptorPoolKey {
-		union {
-			struct {
-				uint16_t uniform_type[UNIFORM_TYPE_MAX]; // Using 16 bits because, for sending arrays, each element is a pool set.
-			};
-			struct {
-				uint64_t key1;
-				uint64_t key2;
-				uint64_t key3;
-			};
-		};
-		bool operator<(const DescriptorPoolKey &p_key) const {
-			if (key1 != p_key.key1) {
-				return key1 < p_key.key1;
-			}
-			if (key2 != p_key.key2) {
-				return key2 < p_key.key2;
-			}
-
-			return key3 < p_key.key3;
-		}
-		DescriptorPoolKey() {
-			key1 = 0;
-			key2 = 0;
-			key3 = 0;
-		}
-	};
-
-	struct DescriptorPool {
-		VkDescriptorPool pool;
-		uint32_t usage;
-	};
-
-	RBMap<DescriptorPoolKey, HashSet<DescriptorPool *>> descriptor_pools;
-	uint32_t max_descriptors_per_pool = 0;
-
-	DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key);
-	void _descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool);
-
-	RID_Owner<Buffer> uniform_buffer_owner;
-	RID_Owner<Buffer> storage_buffer_owner;
-
-	// Texture buffer needs a view.
-	struct TextureBuffer {
-		Buffer buffer;
-		VkBufferView view = VK_NULL_HANDLE;
-	};
-
-	RID_Owner<TextureBuffer> texture_buffer_owner;
-
-	// This structure contains the descriptor set. They _need_ to be allocated
-	// for a shader (and will be erased when this shader is erased), but should
-	// work for other shaders as long as the hash matches. This covers using
-	// them in shader variants.
-	//
-	// Keep also in mind that you can share buffers between descriptor sets, so
-	// the above restriction is not too serious.
-
-	struct UniformSet {
-		uint32_t format = 0;
-		RID shader_id;
-		uint32_t shader_set = 0;
-		DescriptorPool *pool = nullptr;
-		DescriptorPoolKey pool_key;
-		VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
-		//VkPipelineLayout pipeline_layout; // Not owned, inherited from shader.
-		struct AttachableTexture {
-			uint32_t bind;
-			RID texture;
-		};
-
-		LocalVector<AttachableTexture> attachable_textures; // Used for validation.
-		Vector<Texture *> mutable_sampled_textures; // Used for layout change.
-		Vector<Texture *> mutable_storage_textures; // Used for layout change.
-		InvalidationCallback invalidated_callback = nullptr;
-		void *invalidated_callback_userdata = nullptr;
-	};
-
-	RID_Owner<UniformSet> uniform_set_owner;
-
-	/*******************/
-	/**** PIPELINES ****/
-	/*******************/
-
-	// Render pipeline contains ALL the
-	// information required for drawing.
-	// This includes all the rasterizer state
-	// as well as shader used, framebuffer format,
-	// etc.
-	// While the pipeline is just a single object
-	// (VkPipeline) a lot of values are also saved
-	// here to do validation (vulkan does none by
-	// default) and warn the user if something
-	// was not supplied as intended.
-
-	struct RenderPipeline {
-		// Cached values for validation.
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			FramebufferFormatID framebuffer_format = 0;
-			uint32_t render_pass = 0;
-			uint32_t dynamic_state = 0;
-			VertexFormatID vertex_format = 0;
-			bool uses_restart_indices = false;
-			uint32_t primitive_minimum = 0;
-			uint32_t primitive_divisor = 0;
-		} validation;
-#endif
-		// Actual pipeline.
-		RID shader;
-		Vector<uint32_t> set_formats;
-		VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
-		VkPipeline pipeline = VK_NULL_HANDLE;
-		uint32_t push_constant_size = 0;
-		uint32_t push_constant_stages_mask = 0;
-	};
-
-	RID_Owner<RenderPipeline> render_pipeline_owner;
-
-	struct PipelineCacheHeader {
-		uint32_t magic;
-		uint32_t data_size;
-		uint64_t data_hash;
-		uint32_t vendor_id;
-		uint32_t device_id;
-		uint32_t driver_version;
-		uint8_t uuid[VK_UUID_SIZE];
-		uint8_t driver_abi;
-	};
-
-	struct PipelineCache {
-		String file_path;
-		PipelineCacheHeader header = {};
-		size_t current_size = 0;
-		LocalVector<uint8_t> buffer;
-		VkPipelineCache cache_object = VK_NULL_HANDLE;
-	};
-
-	PipelineCache pipelines_cache;
-
-	WorkerThreadPool::TaskID pipelines_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;
-
-	void _load_pipeline_cache();
-	void _update_pipeline_cache(bool p_closing = false);
-	static void _save_pipeline_cache(void *p_data);
-
-	struct ComputePipeline {
-		RID shader;
-		Vector<uint32_t> set_formats;
-		VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
-		VkPipeline pipeline = VK_NULL_HANDLE;
-		uint32_t push_constant_size = 0;
-		uint32_t push_constant_stages_mask = 0;
-		uint32_t local_group_size[3] = { 0, 0, 0 };
-	};
-
-	RID_Owner<ComputePipeline> compute_pipeline_owner;
-
-	/*******************/
-	/**** DRAW LIST ****/
-	/*******************/
-
-	// Draw list contains both the command buffer
-	// used for drawing as well as a LOT of
-	// information used for validation. This
-	// validation is cheap so most of it can
-	// also run in release builds.
-
-	// When using split command lists, this is
-	// implemented internally using secondary command
-	// buffers. As they can be created in threads,
-	// each needs its own command pool.
-
-	struct SplitDrawListAllocator {
-		VkCommandPool command_pool = VK_NULL_HANDLE;
-		Vector<VkCommandBuffer> command_buffers; // One for each frame.
-	};
-
-	Vector<SplitDrawListAllocator> split_draw_list_allocators;
-
-	struct DrawList {
-		VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
-		Rect2i viewport;
-		bool viewport_set = false;
-
-		struct SetState {
-			uint32_t pipeline_expected_format = 0;
-			uint32_t uniform_set_format = 0;
-			VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
-			RID uniform_set;
-			bool bound = false;
-		};
-
-		struct State {
-			SetState sets[MAX_UNIFORM_SETS];
-			uint32_t set_count = 0;
-			RID pipeline;
-			RID pipeline_shader;
-			VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
-			RID vertex_array;
-			RID index_array;
-			uint32_t pipeline_push_constant_stages = 0;
-		} state;
-
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			bool active = true; // Means command buffer was not closed, so you can keep adding things.
-			// Actual render pass values.
-			uint32_t dynamic_state = 0;
-			VertexFormatID vertex_format = INVALID_ID;
-			uint32_t vertex_array_size = 0;
-			uint32_t vertex_max_instances_allowed = 0xFFFFFFFF;
-			bool index_buffer_uses_restart_indices = false;
-			uint32_t index_array_size = 0;
-			uint32_t index_array_max_index = 0;
-			uint32_t index_array_offset = 0;
-			Vector<uint32_t> set_formats;
-			Vector<bool> set_bound;
-			Vector<RID> set_rids;
-			// Last pipeline set values.
-			bool pipeline_active = false;
-			uint32_t pipeline_dynamic_state = 0;
-			VertexFormatID pipeline_vertex_format = INVALID_ID;
-			RID pipeline_shader;
-			bool pipeline_uses_restart_indices = false;
-			uint32_t pipeline_primitive_divisor = 0;
-			uint32_t pipeline_primitive_minimum = 0;
-			uint32_t pipeline_push_constant_size = 0;
-			bool pipeline_push_constant_supplied = false;
-		} validation;
-#else
-		struct Validation {
-			uint32_t vertex_array_size = 0;
-			uint32_t index_array_size = 0;
-			uint32_t index_array_offset;
-		} validation;
-#endif
-	};
-
-	DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split.
-	uint32_t draw_list_subpass_count = 0;
-	uint32_t draw_list_count = 0;
-	VkRenderPass draw_list_render_pass = VK_NULL_HANDLE;
-	VkFramebuffer draw_list_vkframebuffer = VK_NULL_HANDLE;
-#ifdef DEBUG_ENABLED
-	FramebufferFormatID draw_list_framebuffer_format = INVALID_ID;
-#endif
-	uint32_t draw_list_current_subpass = 0;
-
-	bool draw_list_split = false;
-	Vector<RID> draw_list_bound_textures;
-	Vector<RID> draw_list_storage_textures;
-	bool draw_list_unbind_color_textures = false;
-	bool draw_list_unbind_depth_textures = false;
-
-	void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
-	Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count);
-	Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures, bool p_constrained_to_region);
-	_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
-	Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, BitField<BarrierMask> p_post_barrier);
-	Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
-	void _draw_list_free(Rect2i *r_last_viewport = nullptr);
-
-	/**********************/
-	/**** COMPUTE LIST ****/
-	/**********************/
-
-	struct ComputeList {
-		VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
-
-		struct SetState {
-			uint32_t pipeline_expected_format = 0;
-			uint32_t uniform_set_format = 0;
-			VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
-			RID uniform_set;
-			bool bound = false;
-		};
-
-		struct State {
-			HashSet<Texture *> textures_to_sampled_layout;
-			SetState sets[MAX_UNIFORM_SETS];
-			uint32_t set_count = 0;
-			RID pipeline;
-			RID pipeline_shader;
-			uint32_t local_group_size[3] = { 0, 0, 0 };
-			VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
-			uint32_t pipeline_push_constant_stages = 0;
-			bool allow_draw_overlap;
-		} state;
-
-#ifdef DEBUG_ENABLED
-		struct Validation {
-			bool active = true; // Means command buffer was not closed, so you can keep adding things.
-			Vector<uint32_t> set_formats;
-			Vector<bool> set_bound;
-			Vector<RID> set_rids;
-			// Last pipeline set values.
-			bool pipeline_active = false;
-			RID pipeline_shader;
-			uint32_t invalid_set_from = 0;
-			uint32_t pipeline_push_constant_size = 0;
-			bool pipeline_push_constant_supplied = false;
-		} validation;
-#endif
-	};
-
-	ComputeList *compute_list = nullptr;
-
-	void _compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags);
-
-	/**************************/
-	/**** FRAME MANAGEMENT ****/
-	/**************************/
-
-	// This is the frame structure. There are normally
-	// 3 of these (used for triple buffering), or 2
-	// (double buffering). They are cycled constantly.
-	//
-	// It contains two command buffers, one that is
-	// used internally for setting up (creating stuff)
-	// and another used mostly for drawing.
-	//
-	// They also contains a list of things that need
-	// to be disposed of when deleted, which can't
-	// happen immediately due to the asynchronous
-	// nature of the GPU. They will get deleted
-	// when the frame is cycled.
-
-	struct Frame {
-		// List in usage order, from last to free to first to free.
-		List<Buffer> buffers_to_dispose_of;
-		List<Texture> textures_to_dispose_of;
-		List<Framebuffer> framebuffers_to_dispose_of;
-		List<VkSampler> samplers_to_dispose_of;
-		List<Shader> shaders_to_dispose_of;
-		List<VkBufferView> buffer_views_to_dispose_of;
-		List<UniformSet> uniform_sets_to_dispose_of;
-		List<RenderPipeline> render_pipelines_to_dispose_of;
-		List<ComputePipeline> compute_pipelines_to_dispose_of;
-
-		VkCommandPool command_pool = VK_NULL_HANDLE;
-		// Used for filling up newly created buffers with data provided on creation.
-		// Primarily intended to be accessed by worker threads.
-		// Ideally this cmd buffer should use an async transfer queue.
-		VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE;
-		// The main cmd buffer for drawing and compute.
-		// Primarily intended to be used by the main thread to do most stuff.
-		VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE;
-
-		struct Timestamp {
-			String description;
-			uint64_t value = 0;
-		};
-
-		VkQueryPool timestamp_pool;
-
-		TightLocalVector<String> timestamp_names;
-		TightLocalVector<uint64_t> timestamp_cpu_values;
-		uint32_t timestamp_count = 0;
-		TightLocalVector<String> timestamp_result_names;
-		TightLocalVector<uint64_t> timestamp_cpu_result_values;
-		TightLocalVector<uint64_t> timestamp_result_values;
-		uint32_t timestamp_result_count = 0;
-		uint64_t index = 0;
-	};
-
-	uint32_t max_timestamp_query_elements = 0;
-
-	TightLocalVector<Frame> frames; // Frames available, for main device they are cycled (usually 3), for local devices only 1.
-	int frame = 0; // Current frame.
-	int frame_count = 0; // Total amount of frames.
-	uint64_t frames_drawn = 0;
-	RID local_device;
-	bool local_device_processing = false;
-
-	void _free_pending_resources(int p_frame);
-
-	VmaAllocator allocator = nullptr;
-	HashMap<uint32_t, VmaPool> small_allocs_pools;
-	VmaPool _find_or_create_small_allocs_pool(uint32_t p_mem_type_index);
-
-	VulkanContext *context = nullptr;
-
-	uint64_t image_memory = 0;
-	uint64_t buffer_memory = 0;
-
-	void _free_internal(RID p_id);
-	void _flush(bool p_current_frame);
-
-	bool screen_prepared = false;
-
-	template <class T>
-	void _free_rids(T &p_owner, const char *p_type);
-
-	void _finalize_command_bufers();
-	void _begin_frame();
-
-#ifdef DEV_ENABLED
-	HashMap<RID, String> resource_names;
-#endif
-
-	VkSampleCountFlagBits _ensure_supported_sample_count(TextureSamples p_requested_sample_count) const;
-
-public:
-	virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
-	virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
-	virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
-
-	virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D, uint32_t p_layers = 0);
-	virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
-
-	virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const;
-	virtual bool texture_is_shared(RID p_texture);
-	virtual bool texture_is_valid(RID p_texture);
-	virtual TextureFormat texture_get_format(RID p_texture);
-	virtual Size2i texture_size(RID p_texture);
-	virtual uint64_t texture_get_native_handle(RID p_texture);
-
-	virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	/*********************/
-	/**** FRAMEBUFFER ****/
-	/*********************/
-
-	virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
-	virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
-	virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
-	virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
-
-	virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
-	virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
-	virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
-	virtual bool framebuffer_is_valid(RID p_framebuffer) const;
-	virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata);
-
-	virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
-
-	/*****************/
-	/**** SAMPLER ****/
-	/*****************/
-
-	virtual RID sampler_create(const SamplerState &p_state);
-	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const;
-
-	/**********************/
-	/**** VERTEX ARRAY ****/
-	/**********************/
-
-	virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
-
-	// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
-	virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats);
-	virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets = Vector<uint64_t>());
-
-	virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false);
-
-	virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count);
-
-	/****************/
-	/**** SHADER ****/
-	/****************/
-
-	virtual String shader_get_binary_cache_key() const;
-	virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
-
-	virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder = RID());
-	virtual RID shader_create_placeholder();
-
-	virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader);
-
-	/*****************/
-	/**** UNIFORM ****/
-	/*****************/
-
-	virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
-	virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0);
-	virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>());
-
-	virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
-	virtual bool uniform_set_is_valid(RID p_uniform_set);
-	virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
-
-	virtual Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer.
-	virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-	virtual Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0);
-
-	/*************************/
-	/**** RENDER PIPELINE ****/
-	/*************************/
-
-	virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
-	virtual bool render_pipeline_is_valid(RID p_pipeline);
-
-	/**************************/
-	/**** COMPUTE PIPELINE ****/
-	/**************************/
-
-	virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
-	virtual bool compute_pipeline_is_valid(RID p_pipeline);
-
-	/****************/
-	/**** SCREEN ****/
-	/****************/
-
-	virtual int screen_get_width(DisplayServer::WindowID p_screen = 0) const;
-	virtual int screen_get_height(DisplayServer::WindowID p_screen = 0) const;
-	virtual FramebufferFormatID screen_get_framebuffer_format() const;
-
-	/********************/
-	/**** DRAW LISTS ****/
-	/********************/
-
-	virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
-
-	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
-
-	virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
-	virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
-	virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
-	virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array);
-	virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array);
-	virtual void draw_list_set_line_width(DrawListID p_list, float p_width);
-	virtual void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size);
-
-	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
-
-	virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
-	virtual void draw_list_disable_scissor(DrawListID p_list);
-
-	virtual uint32_t draw_list_get_current_pass();
-	virtual DrawListID draw_list_switch_to_next_pass();
-	virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
-
-	virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	/***********************/
-	/**** COMPUTE LISTS ****/
-	/***********************/
-
-	virtual ComputeListID compute_list_begin(bool p_allow_draw_overlap = false);
-	virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline);
-	virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index);
-	virtual void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size);
-	virtual void compute_list_add_barrier(ComputeListID p_list);
-
-	virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
-	virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads);
-	virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset);
-	virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
-
-	virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
-	virtual void full_barrier();
-
-	/**************/
-	/**** FREE ****/
-	/**************/
-
-	virtual void free(RID p_id);
-
-	/****************/
-	/**** Timing ****/
-	/****************/
-
-	virtual void capture_timestamp(const String &p_name);
-	virtual uint32_t get_captured_timestamps_count() const;
-	virtual uint64_t get_captured_timestamps_frame() const;
-	virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const;
-	virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
-	virtual String get_captured_timestamp_name(uint32_t p_index) const;
-
-	/****************/
-	/**** Limits ****/
-	/****************/
-
-	virtual uint64_t limit_get(Limit p_limit) const;
-
-	virtual void prepare_screen_for_drawing();
-	void initialize(VulkanContext *p_context, bool p_local_device = false);
-	void finalize();
-
-	virtual void swap_buffers(); // For main device.
-
-	virtual void submit(); // For local device.
-	virtual void sync(); // For local device.
-
-	virtual uint32_t get_frame_delay() const;
-
-	virtual RenderingDevice *create_local_device();
-
-	virtual uint64_t get_memory_usage(MemoryType p_type) const;
-
-	virtual void set_resource_name(RID p_id, const String p_name);
-
-	virtual void draw_command_begin_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1));
-	virtual void draw_command_insert_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1));
-	virtual void draw_command_end_label();
-
-	virtual String get_device_vendor_name() const;
-	virtual String get_device_name() const;
-	virtual RenderingDevice::DeviceType get_device_type() const;
-	virtual String get_device_api_version() const;
-	virtual String get_device_pipeline_cache_uuid() const;
-
-	virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
-
-	virtual bool has_feature(const Features p_feature) const;
-
-	RenderingDeviceVulkan();
-	~RenderingDeviceVulkan();
-};
-
-#endif // RENDERING_DEVICE_VULKAN_H

+ 163 - 144
drivers/vulkan/vulkan_context.cpp

@@ -412,7 +412,9 @@ Error VulkanContext::_initialize_instance_extensions() {
 
 	// Make sure our core extensions are here
 	register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
-	register_requested_instance_extension(_get_platform_surface_extension(), true);
+	if (_get_platform_surface_extension()) {
+		register_requested_instance_extension(_get_platform_surface_extension(), true);
+	}
 
 	if (_use_validation_layers()) {
 		register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
@@ -1232,21 +1234,24 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
 
 			bool present_supported = false;
 
-			uint32_t device_queue_family_count = 0;
-			vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
-			VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
-			vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
-			for (uint32_t j = 0; j < device_queue_family_count; j++) {
-				if ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
-					VkBool32 supports;
-					err = vkGetPhysicalDeviceSurfaceSupportKHR(
-							physical_devices[i], j, p_surface, &supports);
-					if (err == VK_SUCCESS && supports) {
-						present_supported = true;
-					} else {
-						continue;
+			if (p_surface) {
+				uint32_t device_queue_family_count = 0;
+				vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
+				VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
+				vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
+				for (uint32_t j = 0; j < device_queue_family_count; j++) {
+					if ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
+						VkBool32 supports;
+						err = vkGetPhysicalDeviceSurfaceSupportKHR(
+								physical_devices[i], j, p_surface, &supports);
+						if (err == VK_SUCCESS && supports) {
+							present_supported = true;
+						} else {
+							continue;
+						}
 					}
 				}
+				free(device_queue_props);
 			}
 			String name = String::utf8(props.deviceName);
 			String vendor = "Unknown";
@@ -1276,10 +1281,9 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
 				}
 				vendor_idx++;
 			}
-			free(device_queue_props);
 			print_verbose("  #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
 
-			if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
+			if (present_supported || !p_surface) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
 				switch (props.deviceType) {
 					case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
 						if (type_selected < 4) {
@@ -1509,7 +1513,7 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
 	return OK;
 }
 
-Error VulkanContext::_create_device() {
+Error VulkanContext::_create_device(VkDevice &r_vk_device) {
 	VkResult err;
 	float queue_priorities[1] = { 0.0 };
 	VkDeviceQueueCreateInfo queues[2];
@@ -1624,11 +1628,11 @@ Error VulkanContext::_create_device() {
 	}
 
 	if (vulkan_hooks) {
-		if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) {
+		if (!vulkan_hooks->create_vulkan_device(&sdevice, &r_vk_device)) {
 			return ERR_CANT_CREATE;
 		}
 	} else {
-		err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
+		err = vkCreateDevice(gpu, &sdevice, nullptr, &r_vk_device);
 		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	}
 
@@ -1637,9 +1641,13 @@ Error VulkanContext::_create_device() {
 
 Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
 	// Iterate over each queue to learn whether it supports presenting:
-	VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32));
-	for (uint32_t i = 0; i < queue_family_count; i++) {
-		fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supportsPresent[i]);
+	VkBool32 *supportsPresent = nullptr;
+
+	if (p_surface) {
+		supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32));
+		for (uint32_t i = 0; i < queue_family_count; i++) {
+			fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supportsPresent[i]);
+		}
 	}
 
 	// Search for a graphics and a present queue in the array of queue
@@ -1652,7 +1660,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
 				graphicsQueueFamilyIndex = i;
 			}
 
-			if (supportsPresent[i] == VK_TRUE) {
+			if (p_surface && supportsPresent[i] == VK_TRUE) {
 				graphicsQueueFamilyIndex = i;
 				presentQueueFamilyIndex = i;
 				break;
@@ -1660,7 +1668,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
 		}
 	}
 
-	if (presentQueueFamilyIndex == UINT32_MAX) {
+	if (p_surface && presentQueueFamilyIndex == UINT32_MAX) {
 		// If didn't find a queue that supports both graphics and present, then
 		// find a separate present queue.
 		for (uint32_t i = 0; i < queue_family_count; ++i) {
@@ -1671,17 +1679,22 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
 		}
 	}
 
-	free(supportsPresent);
+	if (p_surface) {
+		free(supportsPresent);
 
-	// Generate error if could not find both a graphics and a present queue.
-	ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE,
-			"Could not find both graphics and present queues\n");
+		// Generate error if could not find both a graphics and a present queue.
+		ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE,
+				"Could not find both graphics and present queues\n");
 
-	graphics_queue_family_index = graphicsQueueFamilyIndex;
-	present_queue_family_index = presentQueueFamilyIndex;
-	separate_present_queue = (graphics_queue_family_index != present_queue_family_index);
+		graphics_queue_family_index = graphicsQueueFamilyIndex;
+		present_queue_family_index = presentQueueFamilyIndex;
+		separate_present_queue = (graphics_queue_family_index != present_queue_family_index);
+	} else {
+		graphics_queue_family_index = graphicsQueueFamilyIndex;
+	}
 
-	_create_device();
+	_create_device(device);
+	driver = memnew(RenderingDeviceDriverVulkan(this, device));
 
 	static PFN_vkGetDeviceProcAddr g_gdpa = nullptr;
 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                                     \
@@ -1705,60 +1718,62 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
 
 	vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue);
 
-	if (!separate_present_queue) {
-		present_queue = graphics_queue;
-	} else {
-		vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue);
-	}
-
-	// Get the list of VkFormat's that are supported:
-	uint32_t formatCount;
-	VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, nullptr);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
-	err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, surfFormats);
-	if (err) {
-		free(surfFormats);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-	// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
-	// the surface has no preferred format.  Otherwise, at least one
-	// supported format will be returned.
-	if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
-		format = VK_FORMAT_B8G8R8A8_UNORM;
-		color_space = surfFormats[0].colorSpace;
-	} else {
-		// These should be ordered with the ones we want to use on top and fallback modes further down
-		// we want a 32bit RGBA unsigned normalized buffer or similar.
-		const VkFormat allowed_formats[] = {
-			VK_FORMAT_B8G8R8A8_UNORM,
-			VK_FORMAT_R8G8B8A8_UNORM
-		};
-		uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
+	if (p_surface) {
+		if (!separate_present_queue) {
+			present_queue = graphics_queue;
+		} else {
+			vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue);
+		}
 
-		if (formatCount < 1) {
+		// Get the list of VkFormat's that are supported:
+		uint32_t formatCount;
+		VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, nullptr);
+		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+		VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
+		err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, surfFormats);
+		if (err) {
 			free(surfFormats);
-			ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
+			ERR_FAIL_V(ERR_CANT_CREATE);
 		}
+		// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+		// the surface has no preferred format.  Otherwise, at least one
+		// supported format will be returned.
+		if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
+			format = VK_FORMAT_B8G8R8A8_UNORM;
+			color_space = surfFormats[0].colorSpace;
+		} else {
+			// These should be ordered with the ones we want to use on top and fallback modes further down
+			// we want a 32bit RGBA unsigned normalized buffer or similar.
+			const VkFormat allowed_formats[] = {
+				VK_FORMAT_B8G8R8A8_UNORM,
+				VK_FORMAT_R8G8B8A8_UNORM
+			};
+			uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
+
+			if (formatCount < 1) {
+				free(surfFormats);
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
+			}
 
-		// Find the first format that we support.
-		format = VK_FORMAT_UNDEFINED;
-		for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
-			for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
-				if (surfFormats[sf].format == allowed_formats[af]) {
-					format = surfFormats[sf].format;
-					color_space = surfFormats[sf].colorSpace;
+			// Find the first format that we support.
+			format = VK_FORMAT_UNDEFINED;
+			for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
+				for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
+					if (surfFormats[sf].format == allowed_formats[af]) {
+						format = surfFormats[sf].format;
+						color_space = surfFormats[sf].colorSpace;
+					}
 				}
 			}
-		}
 
-		if (format == VK_FORMAT_UNDEFINED) {
-			free(surfFormats);
-			ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
+			if (format == VK_FORMAT_UNDEFINED) {
+				free(surfFormats);
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
+			}
 		}
-	}
 
-	free(surfFormats);
+		free(surfFormats);
+	}
 
 	Error serr = _create_semaphores();
 	if (serr) {
@@ -1830,6 +1845,8 @@ VkExtent2D VulkanContext::_compute_swapchain_extent(const VkSurfaceCapabilitiesK
 }
 
 Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) {
+	ERR_FAIL_NULL_V_MSG(_get_platform_surface_extension(), ERR_UNAVAILABLE, "This Vulkan context is headless.");
+
 	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
 
 	if (!device_initialized) {
@@ -1880,22 +1897,20 @@ bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window)
 	return w->swapchain_image_resources != VK_NULL_HANDLE;
 }
 
-VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
+RDD::RenderPassID VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
+	ERR_FAIL_COND_V(!windows.has(p_window), RDD::RenderPassID());
 	Window *w = &windows[p_window];
-	// Vulkan use of currentbuffer.
-	return w->render_pass;
+	return (RDD::RenderPassID)w->render_pass;
 }
 
-VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
-	ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE);
+RDD::FramebufferID VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_window) {
+	ERR_FAIL_COND_V(!windows.has(p_window), RDD::FramebufferID());
+	ERR_FAIL_COND_V(!buffers_prepared, RDD::FramebufferID());
 	Window *w = &windows[p_window];
-	// Vulkan use of currentbuffer.
 	if (w->swapchain_image_resources != VK_NULL_HANDLE) {
-		return w->swapchain_image_resources[w->current_buffer].framebuffer;
+		return (RDD::FramebufferID)w->swapchain_image_resources[w->current_buffer].framebuffer;
 	} else {
-		return VK_NULL_HANDLE;
+		return RDD::FramebufferID();
 	}
 }
 
@@ -2235,7 +2250,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 			/*pPreserveAttachments*/ nullptr,
 		};
 
-		const VkRenderPassCreateInfo2KHR rp_info = {
+		const VkRenderPassCreateInfo2KHR pass_info = {
 			/*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR,
 			/*pNext*/ nullptr,
 			/*flags*/ 0,
@@ -2249,7 +2264,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 			/*pCorrelatedViewMasks*/ nullptr,
 		};
 
-		err = vkCreateRenderPass2KHR(device, &rp_info, nullptr, &window->render_pass);
+		err = vkCreateRenderPass2KHR(device, &pass_info, nullptr, &window->render_pass);
 		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 
 		for (uint32_t i = 0; i < swapchainImageCount; i++) {
@@ -2351,19 +2366,32 @@ Error VulkanContext::initialize() {
 		return err;
 	}
 
+	// Headless? Complete setup now.
+	if (!_get_platform_surface_extension()) {
+		err = _create_physical_device(VK_NULL_HANDLE);
+		if (err != OK) {
+			return err;
+		}
+
+		err = _initialize_queues(VK_NULL_HANDLE);
+		if (err != OK) {
+			return err;
+		}
+	}
+
 	return OK;
 }
 
-void VulkanContext::set_setup_buffer(VkCommandBuffer p_command_buffer) {
-	command_buffer_queue.write[0] = p_command_buffer;
+void VulkanContext::set_setup_buffer(RDD::CommandBufferID p_command_buffer) {
+	command_buffer_queue[0] = (VkCommandBuffer)p_command_buffer.id;
 }
 
-void VulkanContext::append_command_buffer(VkCommandBuffer p_command_buffer) {
+void VulkanContext::append_command_buffer(RDD::CommandBufferID p_command_buffer) {
 	if (command_buffer_queue.size() <= command_buffer_count) {
 		command_buffer_queue.resize(command_buffer_count + 1);
 	}
 
-	command_buffer_queue.write[command_buffer_count] = p_command_buffer;
+	command_buffer_queue[command_buffer_count] = (VkCommandBuffer)p_command_buffer.id;
 	command_buffer_count++;
 }
 
@@ -2389,7 +2417,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
 		submit_info.signalSemaphoreCount = pending_flushable ? 1 : 0;
 		submit_info.pSignalSemaphores = pending_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
 		VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
-		command_buffer_queue.write[0] = nullptr;
+		command_buffer_queue[0] = nullptr;
 		ERR_FAIL_COND(err);
 	}
 
@@ -2415,7 +2443,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
 	vkDeviceWaitIdle(device);
 }
 
-Error VulkanContext::prepare_buffers() {
+Error VulkanContext::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
 	if (!queues_initialized) {
 		return OK;
 	}
@@ -2468,6 +2496,9 @@ Error VulkanContext::prepare_buffers() {
 	return OK;
 }
 
+void VulkanContext::postpare_buffers(RDD::CommandBufferID p_command_buffer) {
+}
+
 Error VulkanContext::swap_buffers() {
 	if (!queues_initialized) {
 		return OK;
@@ -2535,7 +2566,7 @@ Error VulkanContext::swap_buffers() {
 	err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
 	ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit graphics queue. Error code: " + String(string_VkResult(err)));
 
-	command_buffer_queue.write[0] = nullptr;
+	command_buffer_queue[0] = nullptr;
 	command_buffer_count = 1;
 
 	if (separate_present_queue) {
@@ -2690,6 +2721,14 @@ Error VulkanContext::swap_buffers() {
 void VulkanContext::resize_notify() {
 }
 
+RenderingDevice::Capabilities VulkanContext::get_device_capabilities() const {
+	RenderingDevice::Capabilities c;
+	c.device_family = RenderingDevice::DEVICE_VULKAN;
+	c.version_major = VK_API_VERSION_MAJOR(device_api_version);
+	c.version_minor = VK_API_VERSION_MINOR(device_api_version);
+	return c;
+}
+
 VkDevice VulkanContext::get_device() {
 	return device;
 }
@@ -2714,61 +2753,27 @@ VkFormat VulkanContext::get_screen_format() const {
 	return format;
 }
 
-VkPhysicalDeviceLimits VulkanContext::get_device_limits() const {
+const VkPhysicalDeviceLimits &VulkanContext::get_device_limits() const {
 	return gpu_props.limits;
 }
 
 RID VulkanContext::local_device_create() {
 	LocalDevice ld;
 
-	{ // Create device.
-		VkResult err;
-		float queue_priorities[1] = { 0.0 };
-		VkDeviceQueueCreateInfo queues[2];
-		queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
-		queues[0].pNext = nullptr;
-		queues[0].queueFamilyIndex = graphics_queue_family_index;
-		queues[0].queueCount = 1;
-		queues[0].pQueuePriorities = queue_priorities;
-		queues[0].flags = 0;
-
-		uint32_t enabled_extension_count = 0;
-		const char *enabled_extension_names[MAX_EXTENSIONS];
-		ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, RID());
-		for (const CharString &extension_name : enabled_device_extension_names) {
-			enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
-		}
-
-		VkDeviceCreateInfo sdevice = {
-			/*sType =*/VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-			/*pNext */ nullptr,
-			/*flags */ 0,
-			/*queueCreateInfoCount */ 1,
-			/*pQueueCreateInfos */ queues,
-			/*enabledLayerCount */ 0,
-			/*ppEnabledLayerNames */ nullptr,
-			/*enabledExtensionCount */ enabled_extension_count,
-			/*ppEnabledExtensionNames */ (const char *const *)enabled_extension_names,
-			/*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here.
-		};
-		err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device);
-		ERR_FAIL_COND_V(err, RID());
-	}
+	Error err = _create_device(ld.device);
+	ERR_FAIL_COND_V(err, RID());
 
 	{ // Create graphics queue.
 
 		vkGetDeviceQueue(ld.device, graphics_queue_family_index, 0, &ld.queue);
 	}
 
-	return local_device_owner.make_rid(ld);
-}
+	ld.driver = memnew(RenderingDeviceDriverVulkan(this, ld.device));
 
-VkDevice VulkanContext::local_device_get_vk_device(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	return ld->device;
+	return local_device_owner.make_rid(ld);
 }
 
-void VulkanContext::local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count) {
+void VulkanContext::local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) {
 	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
 	ERR_FAIL_COND(ld->waiting);
 
@@ -2779,7 +2784,7 @@ void VulkanContext::local_device_push_command_buffers(RID p_local_device, const
 	submit_info.waitSemaphoreCount = 0;
 	submit_info.pWaitSemaphores = nullptr;
 	submit_info.commandBufferCount = p_count;
-	submit_info.pCommandBuffers = p_buffers;
+	submit_info.pCommandBuffers = (const VkCommandBuffer *)p_buffers;
 	submit_info.signalSemaphoreCount = 0;
 	submit_info.pSignalSemaphores = nullptr;
 
@@ -2808,11 +2813,12 @@ void VulkanContext::local_device_sync(RID p_local_device) {
 
 void VulkanContext::local_device_free(RID p_local_device) {
 	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
+	memdelete(ld->driver);
 	vkDestroyDevice(ld->device, nullptr);
 	local_device_owner.free(p_local_device);
 }
 
-void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
+void VulkanContext::command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
 	if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
 		return;
 	}
@@ -2826,10 +2832,10 @@ void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String
 	label.color[1] = p_color[1];
 	label.color[2] = p_color[2];
 	label.color[3] = p_color[3];
-	CmdBeginDebugUtilsLabelEXT(p_command_buffer, &label);
+	CmdBeginDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label);
 }
 
-void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
+void VulkanContext::command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) {
 	if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
 		return;
 	}
@@ -2842,14 +2848,14 @@ void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, Strin
 	label.color[1] = p_color[1];
 	label.color[2] = p_color[2];
 	label.color[3] = p_color[3];
-	CmdInsertDebugUtilsLabelEXT(p_command_buffer, &label);
+	CmdInsertDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id, &label);
 }
 
-void VulkanContext::command_end_label(VkCommandBuffer p_command_buffer) {
+void VulkanContext::command_end_label(RDD::CommandBufferID p_command_buffer) {
 	if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
 		return;
 	}
-	CmdEndDebugUtilsLabelEXT(p_command_buffer);
+	CmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_command_buffer.id);
 }
 
 void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) {
@@ -2897,12 +2903,25 @@ void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServ
 	_update_swap_chain(&windows[p_window]);
 }
 
+RenderingDeviceDriver *VulkanContext::get_driver(RID p_local_device) {
+	if (p_local_device.is_valid()) {
+		LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
+		ERR_FAIL_NULL_V(ld, nullptr);
+		return ld->driver;
+	} else {
+		return driver;
+	}
+}
+
 VulkanContext::VulkanContext() {
 	command_buffer_queue.resize(1); // First one is always the setup command.
-	command_buffer_queue.write[0] = nullptr;
+	command_buffer_queue[0] = nullptr;
 }
 
 VulkanContext::~VulkanContext() {
+	if (driver) {
+		memdelete(driver);
+	}
 	if (queue_props) {
 		free(queue_props);
 	}

+ 47 - 49
drivers/vulkan/vulkan_context.h

@@ -37,8 +37,9 @@
 #include "core/templates/hash_map.h"
 #include "core/templates/rb_map.h"
 #include "core/templates/rid_owner.h"
+#include "rendering_device_driver_vulkan.h"
 #include "servers/display_server.h"
-#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/renderer_rd/api_context_rd.h"
 
 #ifdef USE_VOLK
 #include <volk.h>
@@ -48,7 +49,7 @@
 
 #include "vulkan_hooks.h"
 
-class VulkanContext {
+class VulkanContext : public ApiContextRD {
 public:
 	struct SubgroupCapabilities {
 		uint32_t size;
@@ -65,14 +66,6 @@ public:
 		String supported_operations_desc() const;
 	};
 
-	struct MultiviewCapabilities {
-		bool is_supported;
-		bool geometry_shader_is_supported;
-		bool tessellation_shader_is_supported;
-		uint32_t max_view_count;
-		uint32_t max_instance_count;
-	};
-
 	struct VRSCapabilities {
 		bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level.
 		bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall.
@@ -115,7 +108,7 @@ private:
 
 	uint32_t instance_api_version = VK_API_VERSION_1_0;
 	SubgroupCapabilities subgroup_capabilities;
-	MultiviewCapabilities multiview_capabilities;
+	RDD::MultiviewCapabilities multiview_capabilities;
 	VRSCapabilities vrs_capabilities;
 	ShaderCapabilities shader_capabilities;
 	StorageBufferCapabilities storage_buffer_capabilities;
@@ -171,10 +164,13 @@ private:
 		bool waiting = false;
 		VkDevice device = VK_NULL_HANDLE;
 		VkQueue queue = VK_NULL_HANDLE;
+		RenderingDeviceDriverVulkan *driver = nullptr;
 	};
 
 	RID_Owner<LocalDevice, true> local_device_owner;
 
+	RenderingDeviceDriverVulkan *driver = nullptr;
+
 	HashMap<DisplayServer::WindowID, Window> windows;
 	uint32_t swapchainImageCount = 0;
 
@@ -182,8 +178,8 @@ private:
 
 	bool prepared = false;
 
-	Vector<VkCommandBuffer> command_buffer_queue;
-	int command_buffer_count = 1;
+	LocalVector<VkCommandBuffer> command_buffer_queue;
+	uint32_t command_buffer_count = 1;
 
 	// Extensions.
 	static bool instance_extensions_initialized;
@@ -250,7 +246,7 @@ private:
 
 	Error _initialize_queues(VkSurfaceKHR p_surface);
 
-	Error _create_device();
+	Error _create_device(VkDevice &r_vk_device);
 
 	Error _clean_up_swap_chain(Window *window);
 
@@ -262,7 +258,7 @@ private:
 	Vector<VkAttachmentReference> _convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs);
 
 protected:
-	virtual const char *_get_platform_surface_extension() const = 0;
+	virtual const char *_get_platform_surface_extension() const { return nullptr; }
 
 	virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height);
 
@@ -277,10 +273,10 @@ public:
 	bool supports_renderpass2() const { return is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); }
 	VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
 
-	uint32_t get_vulkan_major() const { return VK_API_VERSION_MAJOR(device_api_version); };
-	uint32_t get_vulkan_minor() const { return VK_API_VERSION_MINOR(device_api_version); };
+	virtual const char *get_api_name() const override final { return "Vulkan"; };
+	virtual RenderingDevice::Capabilities get_device_capabilities() const override final;
 	const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
-	const MultiviewCapabilities &get_multiview_capabilities() const { return multiview_capabilities; };
+	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const override final { return multiview_capabilities; };
 	const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
 	const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
 	const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
@@ -290,7 +286,7 @@ public:
 	VkDevice get_device();
 	VkPhysicalDevice get_physical_device();
 	VkInstance get_instance() { return inst; }
-	int get_swapchain_image_count() const;
+	virtual int get_swapchain_image_count() const override final;
 	VkQueue get_graphics_queue() const;
 	uint32_t get_graphics_queue_family_index() const;
 
@@ -306,44 +302,46 @@ public:
 		return enabled_device_extension_names.has(extension_name);
 	}
 
-	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
-	int window_get_width(DisplayServer::WindowID p_window = 0);
-	int window_get_height(DisplayServer::WindowID p_window = 0);
-	bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0);
-	void window_destroy(DisplayServer::WindowID p_window_id);
-	VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0);
-	VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0);
+	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override final;
+	virtual int window_get_width(DisplayServer::WindowID p_window = 0) override final;
+	virtual int window_get_height(DisplayServer::WindowID p_window = 0) override final;
+	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) override final;
+	virtual void window_destroy(DisplayServer::WindowID p_window_id) override final;
+	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) override final;
+	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) override final;
 
-	RID local_device_create();
-	VkDevice local_device_get_vk_device(RID p_local_device);
-	void local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count);
-	void local_device_sync(RID p_local_device);
-	void local_device_free(RID p_local_device);
+	virtual RID local_device_create() override final;
+	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) override final;
+	virtual void local_device_sync(RID p_local_device) override final;
+	virtual void local_device_free(RID p_local_device) override final;
 
 	VkFormat get_screen_format() const;
-	VkPhysicalDeviceLimits get_device_limits() const;
+	const VkPhysicalDeviceLimits &get_device_limits() const;
 
-	void set_setup_buffer(VkCommandBuffer p_command_buffer);
-	void append_command_buffer(VkCommandBuffer p_command_buffer);
+	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
+	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
 	void resize_notify();
-	void flush(bool p_flush_setup = false, bool p_flush_pending = false);
-	Error prepare_buffers();
-	Error swap_buffers();
-	Error initialize();
-
-	void command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
-	void command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
-	void command_end_label(VkCommandBuffer p_command_buffer);
+	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) override final;
+	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
+	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
+	virtual Error swap_buffers() override final;
+	virtual Error initialize() override final;
+
+	virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
+	virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) override final;
+	virtual void command_end_label(RDD::CommandBufferID p_command_buffer) override final;
 	void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
 
-	String get_device_vendor_name() const;
-	String get_device_name() const;
-	RenderingDevice::DeviceType get_device_type() const;
-	String get_device_api_version() const;
-	String get_device_pipeline_cache_uuid() const;
+	virtual String get_device_vendor_name() const override final;
+	virtual String get_device_name() const override final;
+	virtual RDD::DeviceType get_device_type() const override final;
+	virtual String get_device_api_version() const override final;
+	virtual String get_device_pipeline_cache_uuid() const override final;
+
+	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) override final;
+	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
 
-	void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
-	DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const;
+	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
 
 	VulkanContext();
 	virtual ~VulkanContext();

+ 2 - 2
main/main.cpp

@@ -1844,8 +1844,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::ARRAY, "rendering/gl_compatibility/force_angle_on_devices", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::DICTIONARY, PROPERTY_HINT_NONE, String())), device_blocklist);
 	}
 
-	// Start with RenderingDevice-based backends. Should be included if any RD driver present.
-#if defined(VULKAN_ENABLED) || defined(D3D12_ENABLED)
+	// Start with RenderingDevice-based backends.
+#ifdef RD_ENABLED
 	renderer_hints = "forward_plus,mobile";
 	default_renderer_mobile = "mobile";
 #endif

+ 73 - 51
platform/android/display_server_android.cpp

@@ -37,11 +37,13 @@
 
 #include "core/config/project_settings.h"
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #include "vulkan_context_android.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#endif
 #endif
 
 #ifdef GLES3_ENABLED
@@ -486,9 +488,6 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
 #ifdef GLES3_ENABLED
 	drivers.push_back("opengl3");
 #endif
-#ifdef D3D12_ENABLED
-	drivers.push_back("d3d12");
-#endif
 #ifdef VULKAN_ENABLED
 	drivers.push_back("vulkan");
 #endif
@@ -518,20 +517,30 @@ void DisplayServerAndroid::register_android_driver() {
 }
 
 void DisplayServerAndroid::reset_window() {
-#if defined(VULKAN_ENABLED)
-	if (rendering_driver == "vulkan") {
-		ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
-		ERR_FAIL_NULL(native_window);
-
-		ERR_FAIL_NULL(context_vulkan);
-		VSyncMode last_vsync_mode = context_vulkan->get_vsync_mode(MAIN_WINDOW_ID);
-		context_vulkan->window_destroy(MAIN_WINDOW_ID);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		VSyncMode last_vsync_mode = context_rd->get_vsync_mode(MAIN_WINDOW_ID);
+		context_rd->window_destroy(MAIN_WINDOW_ID);
 
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
-		if (context_vulkan->window_create(native_window, last_vsync_mode, display_size.width, display_size.height) != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
-			ERR_FAIL_MSG("Failed to reset Vulkan window.");
+
+		union {
+#ifdef VULKAN_ENABLED
+			VulkanContextAndroid::WindowPlatformData vulkan;
+#endif
+		} wpd;
+#ifdef VULKAN_ENABLED
+		if (rendering_driver == "vulkan") {
+			ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
+			ERR_FAIL_NULL(native_window);
+			wpd.vulkan.window = native_window;
+		}
+#endif
+
+		if (context_rd->window_create(MAIN_WINDOW_ID, last_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
+			ERR_FAIL_MSG(vformat("Failed to reset %s window.", context_rd->get_api_name()));
 		}
 	}
 #endif
@@ -554,30 +563,46 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 	}
 #endif
 
-#if defined(VULKAN_ENABLED)
-	context_vulkan = nullptr;
-	rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	context_rd = nullptr;
+	rendering_device = nullptr;
 
+#if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
-		ERR_FAIL_NULL(native_window);
-
-		context_vulkan = memnew(VulkanContextAndroid);
-		if (context_vulkan->initialize() != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
-			ERR_FAIL_MSG("Failed to initialize Vulkan context");
+		context_rd = memnew(VulkanContextAndroid);
+	}
+#endif
+
+	if (context_rd) {
+		if (context_rd->initialize() != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
+			ERR_FAIL_MSG(vformat("Failed to initialize %s context", context_rd->get_api_name()));
 		}
 
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
-		if (context_vulkan->window_create(native_window, p_vsync_mode, display_size.width, display_size.height) != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
-			ERR_FAIL_MSG("Failed to create Vulkan window.");
+
+		union {
+#ifdef VULKAN_ENABLED
+			VulkanContextAndroid::WindowPlatformData vulkan;
+#endif
+		} wpd;
+#ifdef VULKAN_ENABLED
+		if (rendering_driver == "vulkan") {
+			ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
+			ERR_FAIL_NULL(native_window);
+			wpd.vulkan.window = native_window;
+		}
+#endif
+
+		if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
+			ERR_FAIL_MSG(vformat("Failed to create %s window.", context_rd->get_api_name()));
 		}
 
-		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
-		rendering_device_vulkan->initialize(context_vulkan);
+		rendering_device = memnew(RenderingDevice);
+		rendering_device->initialize(context_rd);
 
 		RendererCompositorRD::make_current();
 	}
@@ -590,16 +615,13 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 }
 
 DisplayServerAndroid::~DisplayServerAndroid() {
-#if defined(VULKAN_ENABLED)
-	if (rendering_driver == "vulkan") {
-		if (rendering_device_vulkan) {
-			rendering_device_vulkan->finalize();
-			memdelete(rendering_device_vulkan);
-		}
-
-		if (context_vulkan) {
-			memdelete(context_vulkan);
-		}
+#if defined(RD_ENABLED)
+	if (rendering_device) {
+		rendering_device->finalize();
+		memdelete(rendering_device);
+	}
+	if (context_rd) {
+		memdelete(context_rd);
 	}
 #endif
 }
@@ -690,17 +712,17 @@ void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor
 }
 
 void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
 
 DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_window) const {
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		return context_vulkan->get_vsync_mode(p_window);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		return context_rd->get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;

+ 6 - 6
platform/android/display_server_android.h

@@ -33,9 +33,9 @@
 
 #include "servers/display_server.h"
 
-#if defined(VULKAN_ENABLED)
-class VulkanContextAndroid;
-class RenderingDeviceVulkan;
+#if defined(RD_ENABLED)
+class ApiContextRD;
+class RenderingDevice;
 #endif
 
 class DisplayServerAndroid : public DisplayServer {
@@ -72,9 +72,9 @@ class DisplayServerAndroid : public DisplayServer {
 
 	CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
 
-#if defined(VULKAN_ENABLED)
-	VulkanContextAndroid *context_vulkan = nullptr;
-	RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	ApiContextRD *context_rd = nullptr;
+	RenderingDevice *rendering_device = nullptr;
 #endif
 
 	ObjectID window_attached_instance_id;

+ 6 - 6
platform/android/vulkan_context_android.cpp

@@ -42,14 +42,14 @@ const char *VulkanContextAndroid::_get_platform_surface_extension() const {
 	return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height) {
-	VkAndroidSurfaceCreateInfoKHR createInfo;
+Error VulkanContextAndroid::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+
+	VkAndroidSurfaceCreateInfoKHR createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
-	createInfo.pNext = nullptr;
-	createInfo.flags = 0;
-	createInfo.window = p_window;
+	createInfo.window = wpd->window;
 
-	VkSurfaceKHR surface;
+	VkSurfaceKHR surface = VK_NULL_HANDLE;
 	VkResult err = vkCreateAndroidSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
 	if (err != VK_SUCCESS) {
 		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));

+ 5 - 2
platform/android/vulkan_context_android.h

@@ -38,10 +38,13 @@
 struct ANativeWindow;
 
 class VulkanContextAndroid : public VulkanContext {
-	virtual const char *_get_platform_surface_extension() const override;
+	virtual const char *_get_platform_surface_extension() const override final;
 
 public:
-	Error window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height);
+	struct WindowPlatformData {
+		ANativeWindow *window;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
 	VulkanContextAndroid() = default;
 	~VulkanContextAndroid() override = default;

+ 8 - 6
platform/ios/display_server_ios.h

@@ -34,18 +34,20 @@
 #include "core/input/input.h"
 #include "servers/display_server.h"
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #import "vulkan_context_ios.h"
 
-#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
-
 #ifdef USE_VOLK
 #include <volk.h>
 #else
 #include <vulkan/vulkan.h>
 #endif
 #endif // VULKAN_ENABLED
+#endif // RD_ENABLED
 
 #if defined(GLES3_ENABLED)
 #include "drivers/gles3/rasterizer_gles3.h"
@@ -59,9 +61,9 @@ class DisplayServerIOS : public DisplayServer {
 
 	_THREAD_SAFE_CLASS_
 
-#if defined(VULKAN_ENABLED)
-	VulkanContextIOS *context_vulkan = nullptr;
-	RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	ApiContextRD *context_rd = nullptr;
+	RenderingDevice *rendering_device = nullptr;
 #endif
 
 	id tts = nullptr;

+ 47 - 35
platform/ios/display_server_ios.mm

@@ -62,34 +62,46 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
 		tts = [[TTS_IOS alloc] init];
 	}
 
-#if defined(VULKAN_ENABLED)
-	context_vulkan = nullptr;
-	rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	context_rd = nullptr;
+	rendering_device = nullptr;
 
-	if (rendering_driver == "vulkan") {
-		context_vulkan = memnew(VulkanContextIOS);
-		if (context_vulkan->initialize() != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
-			ERR_FAIL_MSG("Failed to initialize Vulkan context");
-		}
+	CALayer *layer = nullptr;
 
-		CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"];
+	union {
+#ifdef VULKAN_ENABLED
+		VulkanContextIOS::WindowPlatformData vulkan;
+#endif
+	} wpd;
 
+#if defined(VULKAN_ENABLED)
+	if (rendering_driver == "vulkan") {
+		layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"];
 		if (!layer) {
 			ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
 		}
+		wpd.vulkan.layer_ptr = &layer;
+		context_rd = memnew(VulkanContextIOS);
+	}
+#endif
+
+	if (context_rd) {
+		if (context_rd->initialize() != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
+			ERR_FAIL_MSG(vformat("Failed to initialize %s context", context_rd->get_api_name()));
+		}
 
 		Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
-		if (context_vulkan->window_create(MAIN_WINDOW_ID, p_vsync_mode, layer, size.width, size.height) != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
+		if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, size.width, size.height, &wpd) != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
 			r_error = ERR_UNAVAILABLE;
-			ERR_FAIL_MSG("Failed to create Vulkan window.");
+			ERR_FAIL_MSG(vformat("Failed to create %s window.", context_rd->get_api_name()));
 		}
 
-		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
-		rendering_device_vulkan->initialize(context_vulkan);
+		rendering_device = memnew(RenderingDevice);
+		rendering_device->initialize(context_rd);
 
 		RendererCompositorRD::make_current();
 	}
@@ -116,17 +128,17 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
 }
 
 DisplayServerIOS::~DisplayServerIOS() {
-#if defined(VULKAN_ENABLED)
-	if (rendering_device_vulkan) {
-		rendering_device_vulkan->finalize();
-		memdelete(rendering_device_vulkan);
-		rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	if (rendering_device) {
+		rendering_device->finalize();
+		memdelete(rendering_device);
+		rendering_device = nullptr;
 	}
 
-	if (context_vulkan) {
-		context_vulkan->window_destroy(MAIN_WINDOW_ID);
-		memdelete(context_vulkan);
-		context_vulkan = nullptr;
+	if (context_rd) {
+		context_rd->window_destroy(MAIN_WINDOW_ID);
+		memdelete(context_rd);
+		context_rd = nullptr;
 	}
 #endif
 }
@@ -697,9 +709,9 @@ bool DisplayServerIOS::screen_is_kept_on() const {
 void DisplayServerIOS::resize_window(CGSize viewSize) {
 	Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
 
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(MAIN_WINDOW_ID, size.x, size.y);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_resize(MAIN_WINDOW_ID, size.x, size.y);
 	}
 #endif
 
@@ -709,18 +721,18 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
 
 void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
 
 DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		return context_vulkan->get_vsync_mode(p_window);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		return context_rd->get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;

+ 4 - 2
platform/ios/os_ios.h

@@ -41,10 +41,12 @@
 #include "servers/audio_server.h"
 #include "servers/rendering/renderer_compositor.h"
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #import "vulkan_context_ios.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
+#endif
 #endif
 
 class OS_IOS : public OS_Unix {

+ 4 - 2
platform/ios/os_ios.mm

@@ -50,15 +50,17 @@
 #import <dlfcn.h>
 #include <sys/sysctl.h>
 
-#if defined(VULKAN_ENABLED)
+#if defined(RD_ENABLED)
 #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
-
 #import <QuartzCore/CAMetalLayer.h>
+
+#if defined(VULKAN_ENABLED)
 #ifdef USE_VOLK
 #include <volk.h>
 #else
 #include <vulkan/vulkan.h>
 #endif
+#endif // VULKAN_ENABLED
 #endif
 
 // Initialization order between compilation units is not guaranteed,

+ 5 - 2
platform/ios/vulkan_context_ios.h

@@ -38,10 +38,13 @@
 #import <UIKit/UIKit.h>
 
 class VulkanContextIOS : public VulkanContext {
-	virtual const char *_get_platform_surface_extension() const;
+	virtual const char *_get_platform_surface_extension() const override final;
 
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height);
+	struct WindowPlatformData {
+		CALayer *const *layer_ptr;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
 	VulkanContextIOS();
 	~VulkanContextIOS();

+ 7 - 8
platform/ios/vulkan_context_ios.mm

@@ -42,16 +42,15 @@ const char *VulkanContextIOS::_get_platform_surface_extension() const {
 	return VK_MVK_IOS_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) {
-	VkIOSSurfaceCreateInfoMVK createInfo;
+Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+
+	VkIOSSurfaceCreateInfoMVK createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
-	createInfo.pNext = nullptr;
-	createInfo.flags = 0;
-	createInfo.pView = (__bridge const void *)p_metal_layer;
+	createInfo.pView = (__bridge const void *)(*wpd->layer_ptr);
 
-	VkSurfaceKHR surface;
-	VkResult err =
-			vkCreateIOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
+	VkSurfaceKHR surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateIOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 
 	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);

+ 55 - 40
platform/linuxbsd/x11/display_server_x11.cpp

@@ -1707,9 +1707,9 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
 		window_set_transient(p_id, INVALID_WINDOW_ID);
 	}
 
-#ifdef VULKAN_ENABLED
-	if (context_vulkan) {
-		context_vulkan->window_destroy(p_id);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_destroy(p_id);
 	}
 #endif
 #ifdef GLES3_ENABLED
@@ -2233,9 +2233,9 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
 	}
 
 	// Keep rendering context window size in sync
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(p_window, xwa.width, xwa.height);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_resize(p_window, xwa.width, xwa.height);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -3945,9 +3945,9 @@ void DisplayServerX11::_window_changed(XEvent *event) {
 	wd.position = new_rect.position;
 	wd.size = new_rect.size;
 
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_resize(window_id, wd.size.width, wd.size.height);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -5244,9 +5244,9 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
 
 void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 
@@ -5262,9 +5262,9 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
 
 DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		return context_vulkan->get_vsync_mode(p_window);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		return context_rd->get_vsync_mode(p_window);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -5606,10 +5606,21 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
 
 		_update_size_hints(id);
 
-#if defined(VULKAN_ENABLED)
-		if (context_vulkan) {
-			Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height);
-			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
+#if defined(RD_ENABLED)
+		if (context_rd) {
+			union {
+#ifdef VULKAN_ENABLED
+				VulkanContextX11::WindowPlatformData vulkan;
+#endif
+			} wpd;
+#ifdef VULKAN_ENABLED
+			if (rendering_driver == "vulkan") {
+				wpd.vulkan.window = wd.x11_window;
+				wpd.vulkan.display = x11_display;
+			}
+#endif
+			Error err = context_rd->window_create(id, p_vsync_mode, win_rect.size.width, win_rect.size.height, &wpd);
+			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", context_rd->get_api_name()));
 		}
 #endif
 #ifdef GLES3_ENABLED
@@ -6008,14 +6019,19 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	rendering_driver = p_rendering_driver;
 
 	bool driver_found = false;
+#if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_vulkan = memnew(VulkanContextX11);
-		if (context_vulkan->initialize() != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
+		context_rd = memnew(VulkanContextX11);
+	}
+#endif
+
+	if (context_rd) {
+		if (context_rd->initialize() != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
 			r_error = ERR_CANT_CREATE;
-			ERR_FAIL_MSG("Could not initialize Vulkan");
+			ERR_FAIL_MSG(vformat("Could not initialize %s", context_rd->get_api_name()));
 		}
 		driver_found = true;
 	}
@@ -6123,11 +6139,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	}
 	show_window(main_window);
 
-#if defined(VULKAN_ENABLED)
-	if (rendering_driver == "vulkan") {
-		//temporary
-		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
-		rendering_device_vulkan->initialize(context_vulkan);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		rendering_device = memnew(RenderingDevice);
+		rendering_device->initialize(context_rd);
 
 		RendererCompositorRD::make_current();
 	}
@@ -6301,9 +6316,9 @@ DisplayServerX11::~DisplayServerX11() {
 
 	//destroy all windows
 	for (KeyValue<WindowID, WindowData> &E : windows) {
-#ifdef VULKAN_ENABLED
-		if (context_vulkan) {
-			context_vulkan->window_destroy(E.key);
+#if defined(RD_ENABLED)
+		if (context_rd) {
+			context_rd->window_destroy(E.key);
 		}
 #endif
 #ifdef GLES3_ENABLED
@@ -6345,16 +6360,16 @@ DisplayServerX11::~DisplayServerX11() {
 #endif
 
 	//destroy drivers
-#if defined(VULKAN_ENABLED)
-	if (rendering_device_vulkan) {
-		rendering_device_vulkan->finalize();
-		memdelete(rendering_device_vulkan);
-		rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	if (rendering_device) {
+		rendering_device->finalize();
+		memdelete(rendering_device);
+		rendering_device = nullptr;
 	}
 
-	if (context_vulkan) {
-		memdelete(context_vulkan);
-		context_vulkan = nullptr;
+	if (context_rd) {
+		memdelete(context_rd);
+		context_rd = nullptr;
 	}
 #endif
 

+ 7 - 5
platform/linuxbsd/x11/display_server_x11.h

@@ -57,10 +57,12 @@
 #include "x11/gl_manager_x11_egl.h"
 #endif
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #include "x11/vulkan_context_x11.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
+#endif
 #endif
 
 #if defined(DBUS_ENABLED)
@@ -141,9 +143,9 @@ class DisplayServerX11 : public DisplayServer {
 	GLManager_X11 *gl_manager = nullptr;
 	GLManagerEGL_X11 *gl_manager_egl = nullptr;
 #endif
-#if defined(VULKAN_ENABLED)
-	VulkanContextX11 *context_vulkan = nullptr;
-	RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	ApiContextRD *context_rd = nullptr;
+	RenderingDevice *rendering_device = nullptr;
 #endif
 
 #if defined(DBUS_ENABLED)

+ 7 - 7
platform/linuxbsd/x11/vulkan_context_x11.cpp

@@ -42,15 +42,15 @@ const char *VulkanContextX11::_get_platform_surface_extension() const {
 	return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height) {
-	VkXlibSurfaceCreateInfoKHR createInfo;
+Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+
+	VkXlibSurfaceCreateInfoKHR createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
-	createInfo.pNext = nullptr;
-	createInfo.flags = 0;
-	createInfo.dpy = p_display;
-	createInfo.window = p_window;
+	createInfo.dpy = wpd->display;
+	createInfo.window = wpd->window;
 
-	VkSurfaceKHR surface;
+	VkSurfaceKHR surface = VK_NULL_HANDLE;
 	VkResult err = vkCreateXlibSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);

+ 6 - 2
platform/linuxbsd/x11/vulkan_context_x11.h

@@ -38,10 +38,14 @@
 #include <X11/Xlib.h>
 
 class VulkanContextX11 : public VulkanContext {
-	virtual const char *_get_platform_surface_extension() const;
+	virtual const char *_get_platform_surface_extension() const override final;
 
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height);
+	struct WindowPlatformData {
+		::Window window;
+		Display *display;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
 	VulkanContextX11();
 	~VulkanContextX11();

+ 7 - 5
platform/macos/display_server_macos.h

@@ -39,11 +39,13 @@
 #include "gl_manager_macos_legacy.h"
 #endif // GLES3_ENABLED
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #include "vulkan_context_macos.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
 #endif // VULKAN_ENABLED
+#endif // RD_ENABLED
 
 #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
 
@@ -133,9 +135,9 @@ private:
 	GLManagerLegacy_MacOS *gl_manager_legacy = nullptr;
 	GLManagerANGLE_MacOS *gl_manager_angle = nullptr;
 #endif
-#if defined(VULKAN_ENABLED)
-	VulkanContextMacOS *context_vulkan = nullptr;
-	RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	ApiContextRD *context_rd = nullptr;
+	RenderingDevice *rendering_device = nullptr;
 #endif
 	String rendering_driver;
 

+ 48 - 33
platform/macos/display_server_macos.mm

@@ -53,7 +53,7 @@
 #include "drivers/gles3/rasterizer_gles3.h"
 #endif
 
-#if defined(VULKAN_ENABLED)
+#if defined(RD_ENABLED)
 #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
 #endif
 
@@ -179,10 +179,20 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 			[layer setBackgroundColor:bg_color.CGColor];
 		}
 
-#if defined(VULKAN_ENABLED)
-		if (context_vulkan) {
-			Error err = context_vulkan->window_create(window_id_counter, p_vsync_mode, wd.window_view, p_rect.size.width, p_rect.size.height);
-			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context");
+#if defined(RD_ENABLED)
+		if (context_rd) {
+			union {
+#ifdef VULKAN_ENABLED
+				VulkanContextMacOS::WindowPlatformData vulkan;
+#endif
+			} wpd;
+#ifdef VULKAN_ENABLED
+			if (rendering_driver == "vulkan") {
+				wpd.vulkan.view_ptr = &wd.window_view;
+			}
+#endif
+			Error err = context_rd->window_create(window_id_counter, p_vsync_mode, p_rect.size.width, p_rect.size.height, &wpd);
+			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s context", context_rd->get_api_name()));
 		}
 #endif
 #if defined(GLES3_ENABLED)
@@ -232,9 +242,9 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 		gl_manager_angle->window_resize(id, wd.size.width, wd.size.height);
 	}
 #endif
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(id, wd.size.width, wd.size.height);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_resize(id, wd.size.width, wd.size.height);
 	}
 #endif
 
@@ -763,9 +773,9 @@ void DisplayServerMacOS::window_destroy(WindowID p_window) {
 		gl_manager_legacy->window_destroy(p_window);
 	}
 #endif
-#ifdef VULKAN_ENABLED
-	if (context_vulkan) {
-		context_vulkan->window_destroy(p_window);
+#ifdef RD_ENABLED
+	if (context_rd) {
+		context_rd->window_destroy(p_window);
 	}
 #endif
 	windows.erase(p_window);
@@ -782,8 +792,8 @@ void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_hei
 	}
 #endif
 #if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(p_window, p_width, p_height);
+	if (context_rd) {
+		context_rd->window_resize(p_window, p_width, p_height);
 	}
 #endif
 }
@@ -3765,8 +3775,8 @@ void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_
 	}
 #endif
 #if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+	if (context_rd) {
+		context_rd->set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
@@ -3782,8 +3792,8 @@ DisplayServer::VSyncMode DisplayServerMacOS::window_get_vsync_mode(WindowID p_wi
 	}
 #endif
 #if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		return context_vulkan->get_vsync_mode(p_window);
+	if (context_rd) {
+		return context_rd->get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;
@@ -4545,12 +4555,17 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
 		}
 	}
 #endif
+#if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_vulkan = memnew(VulkanContextMacOS);
-		if (context_vulkan->initialize() != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
+		context_rd = memnew(VulkanContextMacOS);
+	}
+#endif
+
+	if (context_rd) {
+		if (context_rd->initialize() != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
 			r_error = ERR_CANT_CREATE;
 			ERR_FAIL_MSG("Could not initialize Vulkan");
 		}
@@ -4585,10 +4600,10 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
 		RasterizerGLES3::make_current(false);
 	}
 #endif
-#if defined(VULKAN_ENABLED)
-	if (rendering_driver == "vulkan") {
-		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
-		rendering_device_vulkan->initialize(context_vulkan);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		rendering_device = memnew(RenderingDevice);
+		rendering_device->initialize(context_rd);
 
 		RendererCompositorRD::make_current();
 	}
@@ -4622,16 +4637,16 @@ DisplayServerMacOS::~DisplayServerMacOS() {
 		gl_manager_angle = nullptr;
 	}
 #endif
-#if defined(VULKAN_ENABLED)
-	if (rendering_device_vulkan) {
-		rendering_device_vulkan->finalize();
-		memdelete(rendering_device_vulkan);
-		rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+	if (rendering_device) {
+		rendering_device->finalize();
+		memdelete(rendering_device);
+		rendering_device = nullptr;
 	}
 
-	if (context_vulkan) {
-		memdelete(context_vulkan);
-		context_vulkan = nullptr;
+	if (context_rd) {
+		memdelete(context_rd);
+		context_rd = nullptr;
 	}
 #endif
 

+ 5 - 2
platform/macos/vulkan_context_macos.h

@@ -38,10 +38,13 @@
 #import <AppKit/AppKit.h>
 
 class VulkanContextMacOS : public VulkanContext {
-	virtual const char *_get_platform_surface_extension() const;
+	virtual const char *_get_platform_surface_extension() const override final;
 
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height);
+	struct WindowPlatformData {
+		const id *view_ptr;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
 	VulkanContextMacOS();
 	~VulkanContextMacOS();

+ 6 - 6
platform/macos/vulkan_context_macos.mm

@@ -42,14 +42,14 @@ const char *VulkanContextMacOS::_get_platform_surface_extension() const {
 	return VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextMacOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) {
-	VkMacOSSurfaceCreateInfoMVK createInfo;
+Error VulkanContextMacOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+
+	VkMacOSSurfaceCreateInfoMVK createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
-	createInfo.pNext = nullptr;
-	createInfo.flags = 0;
-	createInfo.pView = (__bridge const void *)p_window;
+	createInfo.pView = (__bridge const void *)(*wpd->view_ptr);
 
-	VkSurfaceKHR surface;
+	VkSurfaceKHR surface = VK_NULL_HANDLE;
 	VkResult err = vkCreateMacOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);

+ 8 - 4
platform/windows/detect.py

@@ -191,7 +191,11 @@ def get_opts():
         ("mesa_libs", "Path to the MESA/NIR static libraries (required for D3D12)", ""),
         ("dxc_path", "Path to the DirectX Shader Compiler distribution (required for D3D12)", ""),
         ("agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", ""),
-        ("agility_sdk_multiarch", "Whether the Agility SDK DLLs will be stored in arch-specific subdirectories", False),
+        BoolVariable(
+            "agility_sdk_multiarch",
+            "Whether the Agility SDK DLLs will be stored in arch-specific subdirectories",
+            False,
+        ),
         ("pix_path", "Path to the PIX runtime distribution (optional for D3D12)", ""),
     ]
 
@@ -660,14 +664,13 @@ def configure_mingw(env):
     if env["d3d12"]:
         env.AppendUnique(CPPDEFINES=["D3D12_ENABLED"])
         env.Append(LIBS=["d3d12", "dxgi", "dxguid"])
-        env.Append(LIBS=["version"])  # Mesa dependency.
 
         arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
 
         # PIX
         if env["pix_path"] != "":
-            print("PIX runtime is not supported with MinGW.")
-            sys.exit(255)
+            env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
+            env.Append(LIBS=["WinPixEventRuntime"])
 
         # Mesa
         if env["mesa_libs"] == "":
@@ -676,6 +679,7 @@ def configure_mingw(env):
 
         env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
         env.Append(LIBS=["libNIR.windows." + env["arch"]])
+        env.Append(LIBS=["version"])  # Mesa dependency.
 
     if env["opengl3"]:
         env.Append(CPPDEFINES=["GLES3_ENABLED"])

+ 74 - 114
platform/windows/display_server_windows.cpp

@@ -1102,14 +1102,9 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
 		window_set_transient(p_window, INVALID_WINDOW_ID);
 	}
 
-#ifdef VULKAN_ENABLED
-	if (context_vulkan) {
-		context_vulkan->window_destroy(p_window);
-	}
-#endif
-#ifdef D3D12_ENABLED
-	if (context_d3d12) {
-		context_d3d12->window_destroy(p_window);
+#ifdef RD_ENABLED
+	if (context_rd) {
+		context_rd->window_destroy(p_window);
 	}
 #endif
 #ifdef GLES3_ENABLED
@@ -1539,14 +1534,9 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
 	wd.width = w;
 	wd.height = h;
 
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->window_resize(p_window, w, h);
-	}
-#endif
-#if defined(D3D12_ENABLED)
-	if (context_d3d12) {
-		context_d3d12->window_resize(p_window, w, h);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->window_resize(p_window, w, h);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -2594,15 +2584,9 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
 
 void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
-	}
-#endif
-
-#if defined(D3D12_ENABLED)
-	if (context_d3d12) {
-		context_d3d12->set_vsync_mode(p_window, p_vsync_mode);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		context_rd->set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 
@@ -2618,15 +2602,9 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
 
 DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
-	if (context_vulkan) {
-		return context_vulkan->get_vsync_mode(p_window);
-	}
-#endif
-
-#if defined(D3D12_ENABLED)
-	if (context_d3d12) {
-		return context_d3d12->get_vsync_mode(p_window);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		return context_rd->get_vsync_mode(p_window);
 	}
 #endif
 
@@ -3788,19 +3766,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 
 					rect_changed = true;
 				}
-				// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
-				if (window_created && window.context_created) {
-#if defined(VULKAN_ENABLED)
-					if (context_vulkan) {
-						context_vulkan->window_resize(window_id, window.width, window.height);
-					}
-#endif
-#if defined(D3D12_ENABLED)
-					if (context_d3d12) {
-						context_d3d12->window_resize(window_id, window.width, window.height);
-					}
-#endif
+#if defined(RD_ENABLED)
+				if (context_rd && window.context_created) {
+					// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
+					context_rd->window_resize(window_id, window.width, window.height);
 				}
+#endif
 			}
 
 			if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) {
@@ -3826,7 +3797,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 			// Return here to prevent WM_MOVE and WM_SIZE from being sent
 			// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanged#remarks
 			return 0;
-
 		} break;
 
 		case WM_ENTERSIZEMOVE: {
@@ -4352,25 +4322,32 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 			::DwmSetWindowAttribute(wd.hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
 		}
 
+#ifdef RD_ENABLED
+		if (context_rd) {
+			union {
 #ifdef VULKAN_ENABLED
-		if (context_vulkan) {
-			if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
-				memdelete(context_vulkan);
-				context_vulkan = nullptr;
-				windows.erase(id);
-				ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window.");
+				VulkanContextWindows::WindowPlatformData vulkan;
+#endif
+#ifdef D3D12_ENABLED
+				D3D12Context::WindowPlatformData d3d12;
+#endif
+			} wpd;
+#ifdef VULKAN_ENABLED
+			if (rendering_driver == "vulkan") {
+				wpd.vulkan.window = wd.hWnd;
+				wpd.vulkan.instance = hInstance;
 			}
-			wd.context_created = true;
-		}
 #endif
-
 #ifdef D3D12_ENABLED
-		if (context_d3d12) {
-			if (context_d3d12->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
-				memdelete(context_d3d12);
-				context_d3d12 = nullptr;
+			if (rendering_driver == "d3d12") {
+				wpd.d3d12.window = wd.hWnd;
+			}
+#endif
+			if (context_rd->window_create(id, p_vsync_mode, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, &wpd) != OK) {
+				memdelete(context_rd);
+				context_rd = nullptr;
 				windows.erase(id);
-				ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create D3D12 Window.");
+				ERR_FAIL_V_MSG(INVALID_WINDOW_ID, vformat("Failed to create %s Window.", context_rd->get_api_name()));
 			}
 			wd.context_created = true;
 		}
@@ -4673,29 +4650,28 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 
 	_register_raw_input_devices(INVALID_WINDOW_ID);
 
+#if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_vulkan = memnew(VulkanContextWindows);
-		if (context_vulkan->initialize() != OK) {
-			memdelete(context_vulkan);
-			context_vulkan = nullptr;
-			r_error = ERR_UNAVAILABLE;
-			return;
-		}
+		context_rd = memnew(VulkanContextWindows);
 	}
 #endif
 #if defined(D3D12_ENABLED)
 	if (rendering_driver == "d3d12") {
-		context_d3d12 = memnew(D3D12Context);
-		if (context_d3d12->initialize() != OK) {
-			memdelete(context_d3d12);
-			context_d3d12 = nullptr;
+		context_rd = memnew(D3D12Context);
+	}
+#endif
+
+	if (context_rd) {
+		if (context_rd->initialize() != OK) {
+			memdelete(context_rd);
+			context_rd = nullptr;
 			r_error = ERR_UNAVAILABLE;
 			return;
 		}
 	}
 #endif
-	// Init context and rendering device
+// Init context and rendering device
 #if defined(GLES3_ENABLED)
 
 #if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
@@ -4777,18 +4753,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 
 	show_window(MAIN_WINDOW_ID);
 
-#if defined(VULKAN_ENABLED)
-	if (rendering_driver == "vulkan") {
-		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
-		rendering_device_vulkan->initialize(context_vulkan);
-
-		RendererCompositorRD::make_current();
-	}
-#endif
-#if defined(D3D12_ENABLED)
-	if (rendering_driver == "d3d12") {
-		rendering_device_d3d12 = memnew(RenderingDeviceD3D12);
-		rendering_device_d3d12->initialize(context_d3d12);
+#if defined(RD_ENABLED)
+	if (context_rd) {
+		rendering_device = memnew(RenderingDevice);
+		rendering_device->initialize(context_rd);
 
 		RendererCompositorRD::make_current();
 	}
@@ -4851,6 +4819,16 @@ DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_drive
 							"If you have recently updated your video card drivers, try rebooting.",
 							executable_name),
 					"Unable to initialize Vulkan video driver");
+		} else if (p_rendering_driver == "d3d12") {
+			String executable_name = OS::get_singleton()->get_executable_path().get_file();
+			OS::get_singleton()->alert(
+					vformat("Your video card drivers seem not to support the required DirectX 12 version.\n\n"
+							"If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
+							"You can enable the OpenGL 3 driver by starting the engine from the\n"
+							"command line with the command:\n\n    \"%s\" --rendering-driver opengl3\n\n"
+							"If you have recently updated your video card drivers, try rebooting.",
+							executable_name),
+					"Unable to initialize DirectX 12 video driver");
 		} else {
 			OS::get_singleton()->alert(
 					"Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
@@ -4889,14 +4867,9 @@ DisplayServerWindows::~DisplayServerWindows() {
 #endif
 
 	if (windows.has(MAIN_WINDOW_ID)) {
-#ifdef VULKAN_ENABLED
-		if (context_vulkan) {
-			context_vulkan->window_destroy(MAIN_WINDOW_ID);
-		}
-#endif
-#ifdef D3D12_ENABLED
-		if (context_d3d12) {
-			context_d3d12->window_destroy(MAIN_WINDOW_ID);
+#ifdef RD_ENABLED
+		if (context_rd) {
+			context_rd->window_destroy(MAIN_WINDOW_ID);
 		}
 #endif
 		if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
@@ -4906,29 +4879,16 @@ DisplayServerWindows::~DisplayServerWindows() {
 		DestroyWindow(windows[MAIN_WINDOW_ID].hWnd);
 	}
 
-#if defined(VULKAN_ENABLED)
-	if (rendering_device_vulkan) {
-		rendering_device_vulkan->finalize();
-		memdelete(rendering_device_vulkan);
-		rendering_device_vulkan = nullptr;
-	}
-
-	if (context_vulkan) {
-		memdelete(context_vulkan);
-		context_vulkan = nullptr;
-	}
-#endif
-
-#if defined(D3D12_ENABLED)
-	if (rendering_device_d3d12) {
-		rendering_device_d3d12->finalize();
-		memdelete(rendering_device_d3d12);
-		rendering_device_d3d12 = nullptr;
+#ifdef RD_ENABLED
+	if (rendering_device) {
+		rendering_device->finalize();
+		memdelete(rendering_device);
+		rendering_device = nullptr;
 	}
 
-	if (context_d3d12) {
-		memdelete(context_d3d12);
-		context_d3d12 = nullptr;
+	if (context_rd) {
+		memdelete(context_rd);
+		context_rd = nullptr;
 	}
 #endif
 

+ 8 - 12
platform/windows/display_server_windows.h

@@ -52,14 +52,15 @@
 #include "drivers/xaudio2/audio_driver_xaudio2.h"
 #endif
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #include "vulkan_context_win.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
 #endif
-
 #if defined(D3D12_ENABLED)
-#include "drivers/d3d12/rendering_device_d3d12.h"
+#include "drivers/d3d12/d3d12_context.h"
+#endif
 #endif
 
 #if defined(GLES3_ENABLED)
@@ -346,14 +347,9 @@ class DisplayServerWindows : public DisplayServer {
 	GLManagerNative_Windows *gl_manager_native = nullptr;
 #endif
 
-#if defined(VULKAN_ENABLED)
-	VulkanContextWindows *context_vulkan = nullptr;
-	RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
-#endif
-
-#if defined(D3D12_ENABLED)
-	D3D12Context *context_d3d12 = nullptr;
-	RenderingDeviceD3D12 *rendering_device_d3d12 = nullptr;
+#if defined(RD_ENABLED)
+	ApiContextRD *context_rd = nullptr;
+	RenderingDevice *rendering_device = nullptr;
 #endif
 
 	RBMap<int, Vector2> touch_state;

+ 5 - 4
platform/windows/os_windows.h

@@ -46,14 +46,15 @@
 #include "drivers/xaudio2/audio_driver_xaudio2.h"
 #endif
 
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
+
 #if defined(VULKAN_ENABLED)
 #include "vulkan_context_win.h"
-
-#include "drivers/vulkan/rendering_device_vulkan.h"
 #endif
-
 #if defined(D3D12_ENABLED)
-#include "drivers/d3d12/rendering_device_d3d12.h"
+#include "drivers/d3d12/d3d12_context.h"
+#endif
 #endif
 
 #include <io.h>

+ 8 - 7
platform/windows/vulkan_context_win.cpp

@@ -42,14 +42,15 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const {
 	return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
-	VkWin32SurfaceCreateInfoKHR createInfo;
+Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+
+	VkWin32SurfaceCreateInfoKHR createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
-	createInfo.pNext = nullptr;
-	createInfo.flags = 0;
-	createInfo.hinstance = p_instance;
-	createInfo.hwnd = p_window;
-	VkSurfaceKHR surface;
+	createInfo.hinstance = wpd->instance;
+	createInfo.hwnd = wpd->window;
+
+	VkSurfaceKHR surface = VK_NULL_HANDLE;
 	VkResult err = vkCreateWin32SurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);

+ 5 - 1
platform/windows/vulkan_context_win.h

@@ -42,7 +42,11 @@ class VulkanContextWindows : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
+	struct WindowPlatformData {
+		HWND window;
+		HINSTANCE instance;
+	};
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
 	VulkanContextWindows();
 	~VulkanContextWindows();

+ 33 - 0
servers/rendering/renderer_rd/api_context_rd.cpp

@@ -0,0 +1,33 @@
+/**************************************************************************/
+/*  api_context_rd.cpp                                                    */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "api_context_rd.h"
+
+ApiContextRD::~ApiContextRD() {}

+ 85 - 0
servers/rendering/renderer_rd/api_context_rd.h

@@ -0,0 +1,85 @@
+/**************************************************************************/
+/*  api_context_rd.h                                                      */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef API_CONTEXT_RD_H
+#define API_CONTEXT_RD_H
+
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_device_driver.h"
+
+class ApiContextRD {
+public:
+	virtual const char *get_api_name() const = 0;
+	virtual RenderingDevice::Capabilities get_device_capabilities() const = 0;
+	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const = 0;
+
+	virtual int get_swapchain_image_count() const = 0;
+
+	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) = 0;
+	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) = 0;
+	virtual int window_get_width(DisplayServer::WindowID p_window = 0) = 0;
+	virtual int window_get_height(DisplayServer::WindowID p_window = 0) = 0;
+	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) = 0;
+	virtual void window_destroy(DisplayServer::WindowID p_window_id) = 0;
+	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) = 0;
+	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) = 0;
+
+	virtual RID local_device_create() = 0;
+	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) = 0;
+	virtual void local_device_sync(RID p_local_device) = 0;
+	virtual void local_device_free(RID p_local_device) = 0;
+
+	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) = 0;
+	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) = 0;
+	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false) = 0;
+	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
+	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
+	virtual Error swap_buffers() = 0;
+	virtual Error initialize() = 0;
+
+	virtual void command_begin_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0;
+	virtual void command_insert_label(RDD::CommandBufferID p_command_buffer, String p_label_name, const Color &p_color) = 0;
+	virtual void command_end_label(RDD::CommandBufferID p_command_buffer) = 0;
+
+	virtual String get_device_vendor_name() const = 0;
+	virtual String get_device_name() const = 0;
+	virtual RDD::DeviceType get_device_type() const = 0;
+	virtual String get_device_api_version() const = 0;
+	virtual String get_device_pipeline_cache_uuid() const = 0;
+
+	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) = 0;
+	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const = 0;
+
+	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) = 0;
+
+	virtual ~ApiContextRD();
+};
+
+#endif // API_CONTEXT_RD_H

+ 6 - 6
servers/rendering/renderer_rd/shader_rd.cpp

@@ -242,8 +242,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
 
 		current_source = builder.as_string();
 		RD::ShaderStageSPIRVData stage;
-		stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
-		if (stage.spir_v.size() == 0) {
+		stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+		if (stage.spirv.size() == 0) {
 			build_ok = false;
 		} else {
 			stage.shader_stage = RD::SHADER_STAGE_VERTEX;
@@ -260,8 +260,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
 
 		current_source = builder.as_string();
 		RD::ShaderStageSPIRVData stage;
-		stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
-		if (stage.spir_v.size() == 0) {
+		stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+		if (stage.spirv.size() == 0) {
 			build_ok = false;
 		} else {
 			stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
@@ -279,8 +279,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
 		current_source = builder.as_string();
 
 		RD::ShaderStageSPIRVData stage;
-		stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
-		if (stage.spir_v.size() == 0) {
+		stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+		if (stage.spirv.size() == 0) {
 			build_ok = false;
 		} else {
 			stage.shader_stage = RD::SHADER_STAGE_COMPUTE;

+ 2 - 2
servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

@@ -1557,9 +1557,9 @@ uint64_t TextureStorage::texture_get_native_handle(RID p_texture, bool p_srgb) c
 	ERR_FAIL_NULL_V(tex, 0);
 
 	if (p_srgb && tex->rd_texture_srgb.is_valid()) {
-		return RD::get_singleton()->texture_get_native_handle(tex->rd_texture_srgb);
+		return RD::get_singleton()->get_driver_resource(RD::DRIVER_RESOURCE_TEXTURE, tex->rd_texture_srgb);
 	} else {
-		return RD::get_singleton()->texture_get_native_handle(tex->rd_texture);
+		return RD::get_singleton()->get_driver_resource(RD::DRIVER_RESOURCE_TEXTURE, tex->rd_texture);
 	}
 }
 

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 6236 - 835
servers/rendering/rendering_device.cpp


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 587 - 562
servers/rendering/rendering_device.h


+ 1 - 1
servers/rendering/rendering_device_binds.h

@@ -289,7 +289,7 @@ public:
 			if (bytecode[i].size()) {
 				RD::ShaderStageSPIRVData stage;
 				stage.shader_stage = RD::ShaderStage(i);
-				stage.spir_v = bytecode[i];
+				stage.spirv = bytecode[i];
 				stages.push_back(stage);
 			}
 		}

+ 912 - 0
servers/rendering/rendering_device_commons.cpp

@@ -0,0 +1,912 @@
+/**************************************************************************/
+/*  rendering_device_commons.cpp                                          */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_device_commons.h"
+
+/*****************/
+/**** GENERIC ****/
+/*****************/
+
+const char *const RenderingDeviceCommons::FORMAT_NAMES[DATA_FORMAT_MAX] = {
+	"R4G4_Unorm_Pack8",
+	"R4G4B4A4_Unorm_Pack16",
+	"B4G4R4A4_Unorm_Pack16",
+	"R5G6B5_Unorm_Pack16",
+	"B5G6R5_Unorm_Pack16",
+	"R5G5B5A1_Unorm_Pack16",
+	"B5G5R5A1_Unorm_Pack16",
+	"A1R5G5B5_Unorm_Pack16",
+	"R8_Unorm",
+	"R8_Snorm",
+	"R8_Uscaled",
+	"R8_Sscaled",
+	"R8_Uint",
+	"R8_Sint",
+	"R8_Srgb",
+	"R8G8_Unorm",
+	"R8G8_Snorm",
+	"R8G8_Uscaled",
+	"R8G8_Sscaled",
+	"R8G8_Uint",
+	"R8G8_Sint",
+	"R8G8_Srgb",
+	"R8G8B8_Unorm",
+	"R8G8B8_Snorm",
+	"R8G8B8_Uscaled",
+	"R8G8B8_Sscaled",
+	"R8G8B8_Uint",
+	"R8G8B8_Sint",
+	"R8G8B8_Srgb",
+	"B8G8R8_Unorm",
+	"B8G8R8_Snorm",
+	"B8G8R8_Uscaled",
+	"B8G8R8_Sscaled",
+	"B8G8R8_Uint",
+	"B8G8R8_Sint",
+	"B8G8R8_Srgb",
+	"R8G8B8A8_Unorm",
+	"R8G8B8A8_Snorm",
+	"R8G8B8A8_Uscaled",
+	"R8G8B8A8_Sscaled",
+	"R8G8B8A8_Uint",
+	"R8G8B8A8_Sint",
+	"R8G8B8A8_Srgb",
+	"B8G8R8A8_Unorm",
+	"B8G8R8A8_Snorm",
+	"B8G8R8A8_Uscaled",
+	"B8G8R8A8_Sscaled",
+	"B8G8R8A8_Uint",
+	"B8G8R8A8_Sint",
+	"B8G8R8A8_Srgb",
+	"A8B8G8R8_Unorm_Pack32",
+	"A8B8G8R8_Snorm_Pack32",
+	"A8B8G8R8_Uscaled_Pack32",
+	"A8B8G8R8_Sscaled_Pack32",
+	"A8B8G8R8_Uint_Pack32",
+	"A8B8G8R8_Sint_Pack32",
+	"A8B8G8R8_Srgb_Pack32",
+	"A2R10G10B10_Unorm_Pack32",
+	"A2R10G10B10_Snorm_Pack32",
+	"A2R10G10B10_Uscaled_Pack32",
+	"A2R10G10B10_Sscaled_Pack32",
+	"A2R10G10B10_Uint_Pack32",
+	"A2R10G10B10_Sint_Pack32",
+	"A2B10G10R10_Unorm_Pack32",
+	"A2B10G10R10_Snorm_Pack32",
+	"A2B10G10R10_Uscaled_Pack32",
+	"A2B10G10R10_Sscaled_Pack32",
+	"A2B10G10R10_Uint_Pack32",
+	"A2B10G10R10_Sint_Pack32",
+	"R16_Unorm",
+	"R16_Snorm",
+	"R16_Uscaled",
+	"R16_Sscaled",
+	"R16_Uint",
+	"R16_Sint",
+	"R16_Sfloat",
+	"R16G16_Unorm",
+	"R16G16_Snorm",
+	"R16G16_Uscaled",
+	"R16G16_Sscaled",
+	"R16G16_Uint",
+	"R16G16_Sint",
+	"R16G16_Sfloat",
+	"R16G16B16_Unorm",
+	"R16G16B16_Snorm",
+	"R16G16B16_Uscaled",
+	"R16G16B16_Sscaled",
+	"R16G16B16_Uint",
+	"R16G16B16_Sint",
+	"R16G16B16_Sfloat",
+	"R16G16B16A16_Unorm",
+	"R16G16B16A16_Snorm",
+	"R16G16B16A16_Uscaled",
+	"R16G16B16A16_Sscaled",
+	"R16G16B16A16_Uint",
+	"R16G16B16A16_Sint",
+	"R16G16B16A16_Sfloat",
+	"R32_Uint",
+	"R32_Sint",
+	"R32_Sfloat",
+	"R32G32_Uint",
+	"R32G32_Sint",
+	"R32G32_Sfloat",
+	"R32G32B32_Uint",
+	"R32G32B32_Sint",
+	"R32G32B32_Sfloat",
+	"R32G32B32A32_Uint",
+	"R32G32B32A32_Sint",
+	"R32G32B32A32_Sfloat",
+	"R64_Uint",
+	"R64_Sint",
+	"R64_Sfloat",
+	"R64G64_Uint",
+	"R64G64_Sint",
+	"R64G64_Sfloat",
+	"R64G64B64_Uint",
+	"R64G64B64_Sint",
+	"R64G64B64_Sfloat",
+	"R64G64B64A64_Uint",
+	"R64G64B64A64_Sint",
+	"R64G64B64A64_Sfloat",
+	"B10G11R11_Ufloat_Pack32",
+	"E5B9G9R9_Ufloat_Pack32",
+	"D16_Unorm",
+	"X8_D24_Unorm_Pack32",
+	"D32_Sfloat",
+	"S8_Uint",
+	"D16_Unorm_S8_Uint",
+	"D24_Unorm_S8_Uint",
+	"D32_Sfloat_S8_Uint",
+	"Bc1_Rgb_Unorm_Block",
+	"Bc1_Rgb_Srgb_Block",
+	"Bc1_Rgba_Unorm_Block",
+	"Bc1_Rgba_Srgb_Block",
+	"Bc2_Unorm_Block",
+	"Bc2_Srgb_Block",
+	"Bc3_Unorm_Block",
+	"Bc3_Srgb_Block",
+	"Bc4_Unorm_Block",
+	"Bc4_Snorm_Block",
+	"Bc5_Unorm_Block",
+	"Bc5_Snorm_Block",
+	"Bc6H_Ufloat_Block",
+	"Bc6H_Sfloat_Block",
+	"Bc7_Unorm_Block",
+	"Bc7_Srgb_Block",
+	"Etc2_R8G8B8_Unorm_Block",
+	"Etc2_R8G8B8_Srgb_Block",
+	"Etc2_R8G8B8A1_Unorm_Block",
+	"Etc2_R8G8B8A1_Srgb_Block",
+	"Etc2_R8G8B8A8_Unorm_Block",
+	"Etc2_R8G8B8A8_Srgb_Block",
+	"Eac_R11_Unorm_Block",
+	"Eac_R11_Snorm_Block",
+	"Eac_R11G11_Unorm_Block",
+	"Eac_R11G11_Snorm_Block",
+	"Astc_4X4_Unorm_Block",
+	"Astc_4X4_Srgb_Block",
+	"Astc_5X4_Unorm_Block",
+	"Astc_5X4_Srgb_Block",
+	"Astc_5X5_Unorm_Block",
+	"Astc_5X5_Srgb_Block",
+	"Astc_6X5_Unorm_Block",
+	"Astc_6X5_Srgb_Block",
+	"Astc_6X6_Unorm_Block",
+	"Astc_6X6_Srgb_Block",
+	"Astc_8X5_Unorm_Block",
+	"Astc_8X5_Srgb_Block",
+	"Astc_8X6_Unorm_Block",
+	"Astc_8X6_Srgb_Block",
+	"Astc_8X8_Unorm_Block",
+	"Astc_8X8_Srgb_Block",
+	"Astc_10X5_Unorm_Block",
+	"Astc_10X5_Srgb_Block",
+	"Astc_10X6_Unorm_Block",
+	"Astc_10X6_Srgb_Block",
+	"Astc_10X8_Unorm_Block",
+	"Astc_10X8_Srgb_Block",
+	"Astc_10X10_Unorm_Block",
+	"Astc_10X10_Srgb_Block",
+	"Astc_12X10_Unorm_Block",
+	"Astc_12X10_Srgb_Block",
+	"Astc_12X12_Unorm_Block",
+	"Astc_12X12_Srgb_Block",
+	"G8B8G8R8_422_Unorm",
+	"B8G8R8G8_422_Unorm",
+	"G8_B8_R8_3Plane_420_Unorm",
+	"G8_B8R8_2Plane_420_Unorm",
+	"G8_B8_R8_3Plane_422_Unorm",
+	"G8_B8R8_2Plane_422_Unorm",
+	"G8_B8_R8_3Plane_444_Unorm",
+	"R10X6_Unorm_Pack16",
+	"R10X6G10X6_Unorm_2Pack16",
+	"R10X6G10X6B10X6A10X6_Unorm_4Pack16",
+	"G10X6B10X6G10X6R10X6_422_Unorm_4Pack16",
+	"B10X6G10X6R10X6G10X6_422_Unorm_4Pack16",
+	"G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16",
+	"G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16",
+	"G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16",
+	"G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16",
+	"G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16",
+	"R12X4_Unorm_Pack16",
+	"R12X4G12X4_Unorm_2Pack16",
+	"R12X4G12X4B12X4A12X4_Unorm_4Pack16",
+	"G12X4B12X4G12X4R12X4_422_Unorm_4Pack16",
+	"B12X4G12X4R12X4G12X4_422_Unorm_4Pack16",
+	"G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16",
+	"G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16",
+	"G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16",
+	"G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16",
+	"G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16",
+	"G16B16G16R16_422_Unorm",
+	"B16G16R16G16_422_Unorm",
+	"G16_B16_R16_3Plane_420_Unorm",
+	"G16_B16R16_2Plane_420_Unorm",
+	"G16_B16_R16_3Plane_422_Unorm",
+	"G16_B16R16_2Plane_422_Unorm",
+	"G16_B16_R16_3Plane_444_Unorm",
+};
+
+/*****************/
+/**** TEXTURE ****/
+/*****************/
+
+const uint32_t RenderingDeviceCommons::TEXTURE_SAMPLES_COUNT[TEXTURE_SAMPLES_MAX] = { 1, 2, 4, 8, 16, 32, 64 };
+
+uint32_t RenderingDeviceCommons::get_image_format_pixel_size(DataFormat p_format) {
+	switch (p_format) {
+		case DATA_FORMAT_R4G4_UNORM_PACK8:
+			return 1;
+		case DATA_FORMAT_R4G4B4A4_UNORM_PACK16:
+		case DATA_FORMAT_B4G4R4A4_UNORM_PACK16:
+		case DATA_FORMAT_R5G6B5_UNORM_PACK16:
+		case DATA_FORMAT_B5G6R5_UNORM_PACK16:
+		case DATA_FORMAT_R5G5B5A1_UNORM_PACK16:
+		case DATA_FORMAT_B5G5R5A1_UNORM_PACK16:
+		case DATA_FORMAT_A1R5G5B5_UNORM_PACK16:
+			return 2;
+		case DATA_FORMAT_R8_UNORM:
+		case DATA_FORMAT_R8_SNORM:
+		case DATA_FORMAT_R8_USCALED:
+		case DATA_FORMAT_R8_SSCALED:
+		case DATA_FORMAT_R8_UINT:
+		case DATA_FORMAT_R8_SINT:
+		case DATA_FORMAT_R8_SRGB:
+			return 1;
+		case DATA_FORMAT_R8G8_UNORM:
+		case DATA_FORMAT_R8G8_SNORM:
+		case DATA_FORMAT_R8G8_USCALED:
+		case DATA_FORMAT_R8G8_SSCALED:
+		case DATA_FORMAT_R8G8_UINT:
+		case DATA_FORMAT_R8G8_SINT:
+		case DATA_FORMAT_R8G8_SRGB:
+			return 2;
+		case DATA_FORMAT_R8G8B8_UNORM:
+		case DATA_FORMAT_R8G8B8_SNORM:
+		case DATA_FORMAT_R8G8B8_USCALED:
+		case DATA_FORMAT_R8G8B8_SSCALED:
+		case DATA_FORMAT_R8G8B8_UINT:
+		case DATA_FORMAT_R8G8B8_SINT:
+		case DATA_FORMAT_R8G8B8_SRGB:
+		case DATA_FORMAT_B8G8R8_UNORM:
+		case DATA_FORMAT_B8G8R8_SNORM:
+		case DATA_FORMAT_B8G8R8_USCALED:
+		case DATA_FORMAT_B8G8R8_SSCALED:
+		case DATA_FORMAT_B8G8R8_UINT:
+		case DATA_FORMAT_B8G8R8_SINT:
+		case DATA_FORMAT_B8G8R8_SRGB:
+			return 3;
+		case DATA_FORMAT_R8G8B8A8_UNORM:
+		case DATA_FORMAT_R8G8B8A8_SNORM:
+		case DATA_FORMAT_R8G8B8A8_USCALED:
+		case DATA_FORMAT_R8G8B8A8_SSCALED:
+		case DATA_FORMAT_R8G8B8A8_UINT:
+		case DATA_FORMAT_R8G8B8A8_SINT:
+		case DATA_FORMAT_R8G8B8A8_SRGB:
+		case DATA_FORMAT_B8G8R8A8_UNORM:
+		case DATA_FORMAT_B8G8R8A8_SNORM:
+		case DATA_FORMAT_B8G8R8A8_USCALED:
+		case DATA_FORMAT_B8G8R8A8_SSCALED:
+		case DATA_FORMAT_B8G8R8A8_UINT:
+		case DATA_FORMAT_B8G8R8A8_SINT:
+		case DATA_FORMAT_B8G8R8A8_SRGB:
+			return 4;
+		case DATA_FORMAT_A8B8G8R8_UNORM_PACK32:
+		case DATA_FORMAT_A8B8G8R8_SNORM_PACK32:
+		case DATA_FORMAT_A8B8G8R8_USCALED_PACK32:
+		case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32:
+		case DATA_FORMAT_A8B8G8R8_UINT_PACK32:
+		case DATA_FORMAT_A8B8G8R8_SINT_PACK32:
+		case DATA_FORMAT_A8B8G8R8_SRGB_PACK32:
+		case DATA_FORMAT_A2R10G10B10_UNORM_PACK32:
+		case DATA_FORMAT_A2R10G10B10_SNORM_PACK32:
+		case DATA_FORMAT_A2R10G10B10_USCALED_PACK32:
+		case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32:
+		case DATA_FORMAT_A2R10G10B10_UINT_PACK32:
+		case DATA_FORMAT_A2R10G10B10_SINT_PACK32:
+		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
+		case DATA_FORMAT_A2B10G10R10_SNORM_PACK32:
+		case DATA_FORMAT_A2B10G10R10_USCALED_PACK32:
+		case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32:
+		case DATA_FORMAT_A2B10G10R10_UINT_PACK32:
+		case DATA_FORMAT_A2B10G10R10_SINT_PACK32:
+			return 4;
+		case DATA_FORMAT_R16_UNORM:
+		case DATA_FORMAT_R16_SNORM:
+		case DATA_FORMAT_R16_USCALED:
+		case DATA_FORMAT_R16_SSCALED:
+		case DATA_FORMAT_R16_UINT:
+		case DATA_FORMAT_R16_SINT:
+		case DATA_FORMAT_R16_SFLOAT:
+			return 2;
+		case DATA_FORMAT_R16G16_UNORM:
+		case DATA_FORMAT_R16G16_SNORM:
+		case DATA_FORMAT_R16G16_USCALED:
+		case DATA_FORMAT_R16G16_SSCALED:
+		case DATA_FORMAT_R16G16_UINT:
+		case DATA_FORMAT_R16G16_SINT:
+		case DATA_FORMAT_R16G16_SFLOAT:
+			return 4;
+		case DATA_FORMAT_R16G16B16_UNORM:
+		case DATA_FORMAT_R16G16B16_SNORM:
+		case DATA_FORMAT_R16G16B16_USCALED:
+		case DATA_FORMAT_R16G16B16_SSCALED:
+		case DATA_FORMAT_R16G16B16_UINT:
+		case DATA_FORMAT_R16G16B16_SINT:
+		case DATA_FORMAT_R16G16B16_SFLOAT:
+			return 6;
+		case DATA_FORMAT_R16G16B16A16_UNORM:
+		case DATA_FORMAT_R16G16B16A16_SNORM:
+		case DATA_FORMAT_R16G16B16A16_USCALED:
+		case DATA_FORMAT_R16G16B16A16_SSCALED:
+		case DATA_FORMAT_R16G16B16A16_UINT:
+		case DATA_FORMAT_R16G16B16A16_SINT:
+		case DATA_FORMAT_R16G16B16A16_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R32_UINT:
+		case DATA_FORMAT_R32_SINT:
+		case DATA_FORMAT_R32_SFLOAT:
+			return 4;
+		case DATA_FORMAT_R32G32_UINT:
+		case DATA_FORMAT_R32G32_SINT:
+		case DATA_FORMAT_R32G32_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R32G32B32_UINT:
+		case DATA_FORMAT_R32G32B32_SINT:
+		case DATA_FORMAT_R32G32B32_SFLOAT:
+			return 12;
+		case DATA_FORMAT_R32G32B32A32_UINT:
+		case DATA_FORMAT_R32G32B32A32_SINT:
+		case DATA_FORMAT_R32G32B32A32_SFLOAT:
+			return 16;
+		case DATA_FORMAT_R64_UINT:
+		case DATA_FORMAT_R64_SINT:
+		case DATA_FORMAT_R64_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R64G64_UINT:
+		case DATA_FORMAT_R64G64_SINT:
+		case DATA_FORMAT_R64G64_SFLOAT:
+			return 16;
+		case DATA_FORMAT_R64G64B64_UINT:
+		case DATA_FORMAT_R64G64B64_SINT:
+		case DATA_FORMAT_R64G64B64_SFLOAT:
+			return 24;
+		case DATA_FORMAT_R64G64B64A64_UINT:
+		case DATA_FORMAT_R64G64B64A64_SINT:
+		case DATA_FORMAT_R64G64B64A64_SFLOAT:
+			return 32;
+		case DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
+		case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+			return 4;
+		case DATA_FORMAT_D16_UNORM:
+			return 2;
+		case DATA_FORMAT_X8_D24_UNORM_PACK32:
+			return 4;
+		case DATA_FORMAT_D32_SFLOAT:
+			return 4;
+		case DATA_FORMAT_S8_UINT:
+			return 1;
+		case DATA_FORMAT_D16_UNORM_S8_UINT:
+			return 4;
+		case DATA_FORMAT_D24_UNORM_S8_UINT:
+			return 4;
+		case DATA_FORMAT_D32_SFLOAT_S8_UINT:
+			return 5; // ?
+		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
+		case DATA_FORMAT_BC2_UNORM_BLOCK:
+		case DATA_FORMAT_BC2_SRGB_BLOCK:
+		case DATA_FORMAT_BC3_UNORM_BLOCK:
+		case DATA_FORMAT_BC3_SRGB_BLOCK:
+		case DATA_FORMAT_BC4_UNORM_BLOCK:
+		case DATA_FORMAT_BC4_SNORM_BLOCK:
+		case DATA_FORMAT_BC5_UNORM_BLOCK:
+		case DATA_FORMAT_BC5_SNORM_BLOCK:
+		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
+		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
+		case DATA_FORMAT_BC7_UNORM_BLOCK:
+		case DATA_FORMAT_BC7_SRGB_BLOCK:
+			return 1;
+		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+			return 1;
+		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
+			return 1;
+		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
+			return 1;
+		case DATA_FORMAT_G8B8G8R8_422_UNORM:
+		case DATA_FORMAT_B8G8R8G8_422_UNORM:
+			return 4;
+		case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+		case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+		case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+		case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+		case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+			return 4;
+		case DATA_FORMAT_R10X6_UNORM_PACK16:
+		case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16:
+		case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+		case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+		case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+		case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+		case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+		case DATA_FORMAT_R12X4_UNORM_PACK16:
+		case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16:
+		case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+		case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+		case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+		case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+		case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+			return 2;
+		case DATA_FORMAT_G16B16G16R16_422_UNORM:
+		case DATA_FORMAT_B16G16R16G16_422_UNORM:
+		case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+		case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+		case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+		case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+		case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
+			return 8;
+		default: {
+			ERR_PRINT("Format not handled, bug");
+		}
+	}
+
+	return 1;
+}
+
+// https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf
+void RenderingDeviceCommons::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) {
+	switch (p_format) {
+		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
+		case DATA_FORMAT_BC2_UNORM_BLOCK:
+		case DATA_FORMAT_BC2_SRGB_BLOCK:
+		case DATA_FORMAT_BC3_UNORM_BLOCK:
+		case DATA_FORMAT_BC3_SRGB_BLOCK:
+		case DATA_FORMAT_BC4_UNORM_BLOCK:
+		case DATA_FORMAT_BC4_SNORM_BLOCK:
+		case DATA_FORMAT_BC5_UNORM_BLOCK:
+		case DATA_FORMAT_BC5_SNORM_BLOCK:
+		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
+		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
+		case DATA_FORMAT_BC7_UNORM_BLOCK:
+		case DATA_FORMAT_BC7_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
+		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
+		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: {
+			r_w = 4;
+			r_h = 4;
+		} break;
+		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported
+		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: {
+			r_w = 4;
+			r_h = 4;
+		} break;
+		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
+			r_w = 8;
+			r_h = 8;
+		} break;
+		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported
+		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
+			r_w = 4;
+			r_h = 4;
+			return;
+		default: {
+			r_w = 1;
+			r_h = 1;
+		}
+	}
+}
+
+uint32_t RenderingDeviceCommons::get_compressed_image_format_block_byte_size(DataFormat p_format) {
+	switch (p_format) {
+		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
+			return 8;
+		case DATA_FORMAT_BC2_UNORM_BLOCK:
+		case DATA_FORMAT_BC2_SRGB_BLOCK:
+			return 16;
+		case DATA_FORMAT_BC3_UNORM_BLOCK:
+		case DATA_FORMAT_BC3_SRGB_BLOCK:
+			return 16;
+		case DATA_FORMAT_BC4_UNORM_BLOCK:
+		case DATA_FORMAT_BC4_SNORM_BLOCK:
+			return 8;
+		case DATA_FORMAT_BC5_UNORM_BLOCK:
+		case DATA_FORMAT_BC5_SNORM_BLOCK:
+			return 16;
+		case DATA_FORMAT_BC6H_UFLOAT_BLOCK:
+		case DATA_FORMAT_BC6H_SFLOAT_BLOCK:
+			return 16;
+		case DATA_FORMAT_BC7_UNORM_BLOCK:
+		case DATA_FORMAT_BC7_SRGB_BLOCK:
+			return 16;
+		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+			return 8;
+		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+			return 8;
+		case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+			return 16;
+		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
+			return 8;
+		case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
+			return 16;
+		case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
+		case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
+		case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
+			return 16;
+		default: {
+		}
+	}
+	return 1;
+}
+
+uint32_t RenderingDeviceCommons::get_compressed_image_format_pixel_rshift(DataFormat p_format) {
+	switch (p_format) {
+		case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1.
+		case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
+		case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
+		case DATA_FORMAT_BC4_UNORM_BLOCK:
+		case DATA_FORMAT_BC4_SNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+		case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+		case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
+		case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
+			return 1;
+		case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
+		case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: {
+			return 2;
+		}
+		default: {
+		}
+	}
+
+	return 0;
+}
+
+uint32_t RenderingDeviceCommons::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) {
+	ERR_FAIL_COND_V(p_mipmaps == 0, 0);
+	uint32_t w = p_width;
+	uint32_t h = p_height;
+	uint32_t d = p_depth;
+
+	uint32_t size = 0;
+
+	uint32_t pixel_size = get_image_format_pixel_size(p_format);
+	uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format);
+	uint32_t blockw, blockh;
+	get_compressed_image_format_block_dimensions(p_format, blockw, blockh);
+
+	for (uint32_t i = 0; i < p_mipmaps; i++) {
+		uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w;
+		uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h;
+
+		uint32_t s = bw * bh;
+
+		s *= pixel_size;
+		s >>= pixel_rshift;
+		size += s * d;
+		if (r_blockw) {
+			*r_blockw = bw;
+		}
+		if (r_blockh) {
+			*r_blockh = bh;
+		}
+		if (r_depth) {
+			*r_depth = d;
+		}
+		w = MAX(blockw, w >> 1);
+		h = MAX(blockh, h >> 1);
+		d = MAX(1u, d >> 1);
+	}
+
+	return size;
+}
+
+uint32_t RenderingDeviceCommons::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
+	// Formats and block size don't really matter here since they can all go down to 1px (even if block is larger).
+	uint32_t w = p_width;
+	uint32_t h = p_height;
+	uint32_t d = p_depth;
+
+	uint32_t mipmaps = 1;
+
+	while (true) {
+		if (w == 1 && h == 1 && d == 1) {
+			break;
+		}
+
+		w = MAX(1u, w >> 1);
+		h = MAX(1u, h >> 1);
+		d = MAX(1u, d >> 1);
+
+		mipmaps++;
+	}
+
+	return mipmaps;
+}
+
+bool RenderingDeviceCommons::format_has_stencil(DataFormat p_format) {
+	switch (p_format) {
+		case DATA_FORMAT_S8_UINT:
+		case DATA_FORMAT_D16_UNORM_S8_UINT:
+		case DATA_FORMAT_D24_UNORM_S8_UINT:
+		case DATA_FORMAT_D32_SFLOAT_S8_UINT: {
+			return true;
+		}
+		default: {
+		}
+	}
+	return false;
+}
+
+uint32_t RenderingDeviceCommons::format_get_plane_count(DataFormat p_format) {
+	uint32_t planes = 1;
+	switch (p_format) {
+		case DATA_FORMAT_D16_UNORM_S8_UINT:
+		case DATA_FORMAT_D24_UNORM_S8_UINT:
+		case DATA_FORMAT_D32_SFLOAT_S8_UINT: {
+			planes = 2;
+			break;
+		}
+		default: {
+		}
+	}
+	DEV_ASSERT(planes <= MAX_IMAGE_FORMAT_PLANES);
+	return planes;
+}
+
+/*****************/
+/**** SAMPLER ****/
+/*****************/
+
+const Color RenderingDeviceCommons::SAMPLER_BORDER_COLOR_VALUE[SAMPLER_BORDER_COLOR_MAX] = {
+	Color(0, 0, 0, 0),
+	Color(0, 0, 0, 0),
+	Color(0, 0, 0, 1),
+	Color(0, 0, 0, 1),
+	Color(1, 1, 1, 1),
+	Color(1, 1, 1, 1),
+};
+
+/**********************/
+/**** VERTEX ARRAY ****/
+/**********************/
+
+uint32_t RenderingDeviceCommons::get_format_vertex_size(DataFormat p_format) {
+	switch (p_format) {
+		case DATA_FORMAT_R8_UNORM:
+		case DATA_FORMAT_R8_SNORM:
+		case DATA_FORMAT_R8_UINT:
+		case DATA_FORMAT_R8_SINT:
+		case DATA_FORMAT_R8G8_UNORM:
+		case DATA_FORMAT_R8G8_SNORM:
+		case DATA_FORMAT_R8G8_UINT:
+		case DATA_FORMAT_R8G8_SINT:
+		case DATA_FORMAT_R8G8B8_UNORM:
+		case DATA_FORMAT_R8G8B8_SNORM:
+		case DATA_FORMAT_R8G8B8_UINT:
+		case DATA_FORMAT_R8G8B8_SINT:
+		case DATA_FORMAT_B8G8R8_UNORM:
+		case DATA_FORMAT_B8G8R8_SNORM:
+		case DATA_FORMAT_B8G8R8_UINT:
+		case DATA_FORMAT_B8G8R8_SINT:
+		case DATA_FORMAT_R8G8B8A8_UNORM:
+		case DATA_FORMAT_R8G8B8A8_SNORM:
+		case DATA_FORMAT_R8G8B8A8_UINT:
+		case DATA_FORMAT_R8G8B8A8_SINT:
+		case DATA_FORMAT_B8G8R8A8_UNORM:
+		case DATA_FORMAT_B8G8R8A8_SNORM:
+		case DATA_FORMAT_B8G8R8A8_UINT:
+		case DATA_FORMAT_B8G8R8A8_SINT:
+		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
+			return 4;
+		case DATA_FORMAT_R16_UNORM:
+		case DATA_FORMAT_R16_SNORM:
+		case DATA_FORMAT_R16_UINT:
+		case DATA_FORMAT_R16_SINT:
+		case DATA_FORMAT_R16_SFLOAT:
+			return 4;
+		case DATA_FORMAT_R16G16_UNORM:
+		case DATA_FORMAT_R16G16_SNORM:
+		case DATA_FORMAT_R16G16_UINT:
+		case DATA_FORMAT_R16G16_SINT:
+		case DATA_FORMAT_R16G16_SFLOAT:
+			return 4;
+		case DATA_FORMAT_R16G16B16_UNORM:
+		case DATA_FORMAT_R16G16B16_SNORM:
+		case DATA_FORMAT_R16G16B16_UINT:
+		case DATA_FORMAT_R16G16B16_SINT:
+		case DATA_FORMAT_R16G16B16_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R16G16B16A16_UNORM:
+		case DATA_FORMAT_R16G16B16A16_SNORM:
+		case DATA_FORMAT_R16G16B16A16_UINT:
+		case DATA_FORMAT_R16G16B16A16_SINT:
+		case DATA_FORMAT_R16G16B16A16_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R32_UINT:
+		case DATA_FORMAT_R32_SINT:
+		case DATA_FORMAT_R32_SFLOAT:
+			return 4;
+		case DATA_FORMAT_R32G32_UINT:
+		case DATA_FORMAT_R32G32_SINT:
+		case DATA_FORMAT_R32G32_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R32G32B32_UINT:
+		case DATA_FORMAT_R32G32B32_SINT:
+		case DATA_FORMAT_R32G32B32_SFLOAT:
+			return 12;
+		case DATA_FORMAT_R32G32B32A32_UINT:
+		case DATA_FORMAT_R32G32B32A32_SINT:
+		case DATA_FORMAT_R32G32B32A32_SFLOAT:
+			return 16;
+		case DATA_FORMAT_R64_UINT:
+		case DATA_FORMAT_R64_SINT:
+		case DATA_FORMAT_R64_SFLOAT:
+			return 8;
+		case DATA_FORMAT_R64G64_UINT:
+		case DATA_FORMAT_R64G64_SINT:
+		case DATA_FORMAT_R64G64_SFLOAT:
+			return 16;
+		case DATA_FORMAT_R64G64B64_UINT:
+		case DATA_FORMAT_R64G64B64_SINT:
+		case DATA_FORMAT_R64G64B64_SFLOAT:
+			return 24;
+		case DATA_FORMAT_R64G64B64A64_UINT:
+		case DATA_FORMAT_R64G64B64A64_SINT:
+		case DATA_FORMAT_R64G64B64A64_SFLOAT:
+			return 32;
+		default:
+			return 0;
+	}
+}
+
+/****************/
+/**** SHADER ****/
+/****************/
+
+const char *RenderingDeviceCommons::SHADER_STAGE_NAMES[SHADER_STAGE_MAX] = {
+	"Vertex",
+	"Fragment",
+	"TesselationControl",
+	"TesselationEvaluation",
+	"Compute",
+};

+ 921 - 0
servers/rendering/rendering_device_commons.h

@@ -0,0 +1,921 @@
+/**************************************************************************/
+/*  rendering_device_commons.h                                            */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_DEVICE_COMMONS_H
+#define RENDERING_DEVICE_COMMONS_H
+
+#include "core/object/object.h"
+#include "core/variant/type_info.h"
+
+#define STEPIFY(m_number, m_alignment) ((((m_number) + ((m_alignment)-1)) / (m_alignment)) * (m_alignment))
+
+class RenderingDeviceCommons : public Object {
+	////////////////////////////////////////////
+	// PUBLIC STUFF
+	// Exposed by RenderingDevice, and shared
+	// with RenderingDeviceDriver.
+	////////////////////////////////////////////
+public:
+	/*****************/
+	/**** GENERIC ****/
+	/*****************/
+
+	static const int INVALID_ID = -1;
+
+	enum DataFormat {
+		DATA_FORMAT_R4G4_UNORM_PACK8,
+		DATA_FORMAT_R4G4B4A4_UNORM_PACK16,
+		DATA_FORMAT_B4G4R4A4_UNORM_PACK16,
+		DATA_FORMAT_R5G6B5_UNORM_PACK16,
+		DATA_FORMAT_B5G6R5_UNORM_PACK16,
+		DATA_FORMAT_R5G5B5A1_UNORM_PACK16,
+		DATA_FORMAT_B5G5R5A1_UNORM_PACK16,
+		DATA_FORMAT_A1R5G5B5_UNORM_PACK16,
+		DATA_FORMAT_R8_UNORM,
+		DATA_FORMAT_R8_SNORM,
+		DATA_FORMAT_R8_USCALED,
+		DATA_FORMAT_R8_SSCALED,
+		DATA_FORMAT_R8_UINT,
+		DATA_FORMAT_R8_SINT,
+		DATA_FORMAT_R8_SRGB,
+		DATA_FORMAT_R8G8_UNORM,
+		DATA_FORMAT_R8G8_SNORM,
+		DATA_FORMAT_R8G8_USCALED,
+		DATA_FORMAT_R8G8_SSCALED,
+		DATA_FORMAT_R8G8_UINT,
+		DATA_FORMAT_R8G8_SINT,
+		DATA_FORMAT_R8G8_SRGB,
+		DATA_FORMAT_R8G8B8_UNORM,
+		DATA_FORMAT_R8G8B8_SNORM,
+		DATA_FORMAT_R8G8B8_USCALED,
+		DATA_FORMAT_R8G8B8_SSCALED,
+		DATA_FORMAT_R8G8B8_UINT,
+		DATA_FORMAT_R8G8B8_SINT,
+		DATA_FORMAT_R8G8B8_SRGB,
+		DATA_FORMAT_B8G8R8_UNORM,
+		DATA_FORMAT_B8G8R8_SNORM,
+		DATA_FORMAT_B8G8R8_USCALED,
+		DATA_FORMAT_B8G8R8_SSCALED,
+		DATA_FORMAT_B8G8R8_UINT,
+		DATA_FORMAT_B8G8R8_SINT,
+		DATA_FORMAT_B8G8R8_SRGB,
+		DATA_FORMAT_R8G8B8A8_UNORM,
+		DATA_FORMAT_R8G8B8A8_SNORM,
+		DATA_FORMAT_R8G8B8A8_USCALED,
+		DATA_FORMAT_R8G8B8A8_SSCALED,
+		DATA_FORMAT_R8G8B8A8_UINT,
+		DATA_FORMAT_R8G8B8A8_SINT,
+		DATA_FORMAT_R8G8B8A8_SRGB,
+		DATA_FORMAT_B8G8R8A8_UNORM,
+		DATA_FORMAT_B8G8R8A8_SNORM,
+		DATA_FORMAT_B8G8R8A8_USCALED,
+		DATA_FORMAT_B8G8R8A8_SSCALED,
+		DATA_FORMAT_B8G8R8A8_UINT,
+		DATA_FORMAT_B8G8R8A8_SINT,
+		DATA_FORMAT_B8G8R8A8_SRGB,
+		DATA_FORMAT_A8B8G8R8_UNORM_PACK32,
+		DATA_FORMAT_A8B8G8R8_SNORM_PACK32,
+		DATA_FORMAT_A8B8G8R8_USCALED_PACK32,
+		DATA_FORMAT_A8B8G8R8_SSCALED_PACK32,
+		DATA_FORMAT_A8B8G8R8_UINT_PACK32,
+		DATA_FORMAT_A8B8G8R8_SINT_PACK32,
+		DATA_FORMAT_A8B8G8R8_SRGB_PACK32,
+		DATA_FORMAT_A2R10G10B10_UNORM_PACK32,
+		DATA_FORMAT_A2R10G10B10_SNORM_PACK32,
+		DATA_FORMAT_A2R10G10B10_USCALED_PACK32,
+		DATA_FORMAT_A2R10G10B10_SSCALED_PACK32,
+		DATA_FORMAT_A2R10G10B10_UINT_PACK32,
+		DATA_FORMAT_A2R10G10B10_SINT_PACK32,
+		DATA_FORMAT_A2B10G10R10_UNORM_PACK32,
+		DATA_FORMAT_A2B10G10R10_SNORM_PACK32,
+		DATA_FORMAT_A2B10G10R10_USCALED_PACK32,
+		DATA_FORMAT_A2B10G10R10_SSCALED_PACK32,
+		DATA_FORMAT_A2B10G10R10_UINT_PACK32,
+		DATA_FORMAT_A2B10G10R10_SINT_PACK32,
+		DATA_FORMAT_R16_UNORM,
+		DATA_FORMAT_R16_SNORM,
+		DATA_FORMAT_R16_USCALED,
+		DATA_FORMAT_R16_SSCALED,
+		DATA_FORMAT_R16_UINT,
+		DATA_FORMAT_R16_SINT,
+		DATA_FORMAT_R16_SFLOAT,
+		DATA_FORMAT_R16G16_UNORM,
+		DATA_FORMAT_R16G16_SNORM,
+		DATA_FORMAT_R16G16_USCALED,
+		DATA_FORMAT_R16G16_SSCALED,
+		DATA_FORMAT_R16G16_UINT,
+		DATA_FORMAT_R16G16_SINT,
+		DATA_FORMAT_R16G16_SFLOAT,
+		DATA_FORMAT_R16G16B16_UNORM,
+		DATA_FORMAT_R16G16B16_SNORM,
+		DATA_FORMAT_R16G16B16_USCALED,
+		DATA_FORMAT_R16G16B16_SSCALED,
+		DATA_FORMAT_R16G16B16_UINT,
+		DATA_FORMAT_R16G16B16_SINT,
+		DATA_FORMAT_R16G16B16_SFLOAT,
+		DATA_FORMAT_R16G16B16A16_UNORM,
+		DATA_FORMAT_R16G16B16A16_SNORM,
+		DATA_FORMAT_R16G16B16A16_USCALED,
+		DATA_FORMAT_R16G16B16A16_SSCALED,
+		DATA_FORMAT_R16G16B16A16_UINT,
+		DATA_FORMAT_R16G16B16A16_SINT,
+		DATA_FORMAT_R16G16B16A16_SFLOAT,
+		DATA_FORMAT_R32_UINT,
+		DATA_FORMAT_R32_SINT,
+		DATA_FORMAT_R32_SFLOAT,
+		DATA_FORMAT_R32G32_UINT,
+		DATA_FORMAT_R32G32_SINT,
+		DATA_FORMAT_R32G32_SFLOAT,
+		DATA_FORMAT_R32G32B32_UINT,
+		DATA_FORMAT_R32G32B32_SINT,
+		DATA_FORMAT_R32G32B32_SFLOAT,
+		DATA_FORMAT_R32G32B32A32_UINT,
+		DATA_FORMAT_R32G32B32A32_SINT,
+		DATA_FORMAT_R32G32B32A32_SFLOAT,
+		DATA_FORMAT_R64_UINT,
+		DATA_FORMAT_R64_SINT,
+		DATA_FORMAT_R64_SFLOAT,
+		DATA_FORMAT_R64G64_UINT,
+		DATA_FORMAT_R64G64_SINT,
+		DATA_FORMAT_R64G64_SFLOAT,
+		DATA_FORMAT_R64G64B64_UINT,
+		DATA_FORMAT_R64G64B64_SINT,
+		DATA_FORMAT_R64G64B64_SFLOAT,
+		DATA_FORMAT_R64G64B64A64_UINT,
+		DATA_FORMAT_R64G64B64A64_SINT,
+		DATA_FORMAT_R64G64B64A64_SFLOAT,
+		DATA_FORMAT_B10G11R11_UFLOAT_PACK32,
+		DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32,
+		DATA_FORMAT_D16_UNORM,
+		DATA_FORMAT_X8_D24_UNORM_PACK32,
+		DATA_FORMAT_D32_SFLOAT,
+		DATA_FORMAT_S8_UINT,
+		DATA_FORMAT_D16_UNORM_S8_UINT,
+		DATA_FORMAT_D24_UNORM_S8_UINT,
+		DATA_FORMAT_D32_SFLOAT_S8_UINT,
+		DATA_FORMAT_BC1_RGB_UNORM_BLOCK,
+		DATA_FORMAT_BC1_RGB_SRGB_BLOCK,
+		DATA_FORMAT_BC1_RGBA_UNORM_BLOCK,
+		DATA_FORMAT_BC1_RGBA_SRGB_BLOCK,
+		DATA_FORMAT_BC2_UNORM_BLOCK,
+		DATA_FORMAT_BC2_SRGB_BLOCK,
+		DATA_FORMAT_BC3_UNORM_BLOCK,
+		DATA_FORMAT_BC3_SRGB_BLOCK,
+		DATA_FORMAT_BC4_UNORM_BLOCK,
+		DATA_FORMAT_BC4_SNORM_BLOCK,
+		DATA_FORMAT_BC5_UNORM_BLOCK,
+		DATA_FORMAT_BC5_SNORM_BLOCK,
+		DATA_FORMAT_BC6H_UFLOAT_BLOCK,
+		DATA_FORMAT_BC6H_SFLOAT_BLOCK,
+		DATA_FORMAT_BC7_UNORM_BLOCK,
+		DATA_FORMAT_BC7_SRGB_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
+		DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
+		DATA_FORMAT_EAC_R11_UNORM_BLOCK,
+		DATA_FORMAT_EAC_R11_SNORM_BLOCK,
+		DATA_FORMAT_EAC_R11G11_UNORM_BLOCK,
+		DATA_FORMAT_EAC_R11G11_SNORM_BLOCK,
+		DATA_FORMAT_ASTC_4x4_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_4x4_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_5x4_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_5x4_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_5x5_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_5x5_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_6x5_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_6x5_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_6x6_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_6x6_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_8x5_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_8x5_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_8x6_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_8x6_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_8x8_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_8x8_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_10x5_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_10x5_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_10x6_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_10x6_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_10x8_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_10x8_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_10x10_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_10x10_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_12x10_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_12x10_SRGB_BLOCK,
+		DATA_FORMAT_ASTC_12x12_UNORM_BLOCK,
+		DATA_FORMAT_ASTC_12x12_SRGB_BLOCK,
+		DATA_FORMAT_G8B8G8R8_422_UNORM,
+		DATA_FORMAT_B8G8R8G8_422_UNORM,
+		DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
+		DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+		DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
+		DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM,
+		DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
+		DATA_FORMAT_R10X6_UNORM_PACK16,
+		DATA_FORMAT_R10X6G10X6_UNORM_2PACK16,
+		DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+		DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
+		DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
+		DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
+		DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
+		DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
+		DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
+		DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
+		DATA_FORMAT_R12X4_UNORM_PACK16,
+		DATA_FORMAT_R12X4G12X4_UNORM_2PACK16,
+		DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
+		DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
+		DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
+		DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
+		DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
+		DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
+		DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
+		DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
+		DATA_FORMAT_G16B16G16R16_422_UNORM,
+		DATA_FORMAT_B16G16R16G16_422_UNORM,
+		DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
+		DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM,
+		DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
+		DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM,
+		DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
+		DATA_FORMAT_MAX,
+	};
+
+	enum CompareOperator {
+		COMPARE_OP_NEVER,
+		COMPARE_OP_LESS,
+		COMPARE_OP_EQUAL,
+		COMPARE_OP_LESS_OR_EQUAL,
+		COMPARE_OP_GREATER,
+		COMPARE_OP_NOT_EQUAL,
+		COMPARE_OP_GREATER_OR_EQUAL,
+		COMPARE_OP_ALWAYS,
+		COMPARE_OP_MAX
+	};
+
+	/*****************/
+	/**** TEXTURE ****/
+	/*****************/
+
+	enum TextureType {
+		TEXTURE_TYPE_1D,
+		TEXTURE_TYPE_2D,
+		TEXTURE_TYPE_3D,
+		TEXTURE_TYPE_CUBE,
+		TEXTURE_TYPE_1D_ARRAY,
+		TEXTURE_TYPE_2D_ARRAY,
+		TEXTURE_TYPE_CUBE_ARRAY,
+		TEXTURE_TYPE_MAX,
+	};
+
+	enum TextureSamples {
+		TEXTURE_SAMPLES_1,
+		TEXTURE_SAMPLES_2,
+		TEXTURE_SAMPLES_4,
+		TEXTURE_SAMPLES_8,
+		TEXTURE_SAMPLES_16,
+		TEXTURE_SAMPLES_32,
+		TEXTURE_SAMPLES_64,
+		TEXTURE_SAMPLES_MAX,
+	};
+
+	enum TextureUsageBits {
+		TEXTURE_USAGE_SAMPLING_BIT = (1 << 0),
+		TEXTURE_USAGE_COLOR_ATTACHMENT_BIT = (1 << 1),
+		TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = (1 << 2),
+		TEXTURE_USAGE_STORAGE_BIT = (1 << 3),
+		TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4),
+		TEXTURE_USAGE_CPU_READ_BIT = (1 << 5),
+		TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
+		TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
+		TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
+		TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9),
+		TEXTURE_USAGE_VRS_ATTACHMENT_BIT = (1 << 10),
+	};
+
+	struct TextureFormat {
+		DataFormat format = DATA_FORMAT_R8_UNORM;
+		uint32_t width = 1;
+		uint32_t height = 1;
+		uint32_t depth = 1;
+		uint32_t array_layers = 1;
+		uint32_t mipmaps = 1;
+		TextureType texture_type = TEXTURE_TYPE_2D;
+		TextureSamples samples = TEXTURE_SAMPLES_1;
+		uint32_t usage_bits = 0;
+		Vector<DataFormat> shareable_formats;
+		bool is_resolve_buffer = false;
+
+		bool operator==(const TextureFormat &b) const {
+			if (format != b.format) {
+				return false;
+			} else if (width != b.width) {
+				return false;
+			} else if (height != b.height) {
+				return false;
+			} else if (depth != b.depth) {
+				return false;
+			} else if (array_layers != b.array_layers) {
+				return false;
+			} else if (mipmaps != b.mipmaps) {
+				return false;
+			} else if (texture_type != b.texture_type) {
+				return false;
+			} else if (samples != b.samples) {
+				return false;
+			} else if (usage_bits != b.usage_bits) {
+				return false;
+			} else if (shareable_formats != b.shareable_formats) {
+				return false;
+			} else {
+				return true;
+			}
+		}
+	};
+
+	enum TextureSwizzle {
+		TEXTURE_SWIZZLE_IDENTITY,
+		TEXTURE_SWIZZLE_ZERO,
+		TEXTURE_SWIZZLE_ONE,
+		TEXTURE_SWIZZLE_R,
+		TEXTURE_SWIZZLE_G,
+		TEXTURE_SWIZZLE_B,
+		TEXTURE_SWIZZLE_A,
+		TEXTURE_SWIZZLE_MAX
+	};
+
+	enum TextureSliceType {
+		TEXTURE_SLICE_2D,
+		TEXTURE_SLICE_CUBEMAP,
+		TEXTURE_SLICE_3D,
+		TEXTURE_SLICE_2D_ARRAY,
+	};
+
+	/*****************/
+	/**** SAMPLER ****/
+	/*****************/
+
+	enum SamplerFilter {
+		SAMPLER_FILTER_NEAREST,
+		SAMPLER_FILTER_LINEAR,
+	};
+
+	enum SamplerRepeatMode {
+		SAMPLER_REPEAT_MODE_REPEAT,
+		SAMPLER_REPEAT_MODE_MIRRORED_REPEAT,
+		SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE,
+		SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER,
+		SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE,
+		SAMPLER_REPEAT_MODE_MAX
+	};
+
+	enum SamplerBorderColor {
+		SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+		SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK,
+		SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
+		SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK,
+		SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
+		SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE,
+		SAMPLER_BORDER_COLOR_MAX
+	};
+
+	struct SamplerState {
+		SamplerFilter mag_filter = SAMPLER_FILTER_NEAREST;
+		SamplerFilter min_filter = SAMPLER_FILTER_NEAREST;
+		SamplerFilter mip_filter = SAMPLER_FILTER_NEAREST;
+		SamplerRepeatMode repeat_u = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+		SamplerRepeatMode repeat_v = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+		SamplerRepeatMode repeat_w = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+		float lod_bias = 0.0f;
+		bool use_anisotropy = false;
+		float anisotropy_max = 1.0f;
+		bool enable_compare = false;
+		CompareOperator compare_op = COMPARE_OP_ALWAYS;
+		float min_lod = 0.0f;
+		float max_lod = 1e20; // Something very large should do.
+		SamplerBorderColor border_color = SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+		bool unnormalized_uvw = false;
+	};
+
+	/**********************/
+	/**** VERTEX ARRAY ****/
+	/**********************/
+
+	enum IndexBufferFormat {
+		INDEX_BUFFER_FORMAT_UINT16,
+		INDEX_BUFFER_FORMAT_UINT32,
+	};
+
+	enum VertexFrequency {
+		VERTEX_FREQUENCY_VERTEX,
+		VERTEX_FREQUENCY_INSTANCE,
+	};
+
+	struct VertexAttribute {
+		uint32_t location = 0; // Shader location.
+		uint32_t offset = 0;
+		DataFormat format = DATA_FORMAT_MAX;
+		uint32_t stride = 0;
+		VertexFrequency frequency = VERTEX_FREQUENCY_VERTEX;
+	};
+
+	/*********************/
+	/**** FRAMEBUFFER ****/
+	/*********************/
+
+	static const int32_t ATTACHMENT_UNUSED = -1;
+
+	/****************/
+	/**** SHADER ****/
+	/****************/
+
+	enum ShaderStage {
+		SHADER_STAGE_VERTEX,
+		SHADER_STAGE_FRAGMENT,
+		SHADER_STAGE_TESSELATION_CONTROL,
+		SHADER_STAGE_TESSELATION_EVALUATION,
+		SHADER_STAGE_COMPUTE,
+		SHADER_STAGE_MAX,
+		SHADER_STAGE_VERTEX_BIT = (1 << SHADER_STAGE_VERTEX),
+		SHADER_STAGE_FRAGMENT_BIT = (1 << SHADER_STAGE_FRAGMENT),
+		SHADER_STAGE_TESSELATION_CONTROL_BIT = (1 << SHADER_STAGE_TESSELATION_CONTROL),
+		SHADER_STAGE_TESSELATION_EVALUATION_BIT = (1 << SHADER_STAGE_TESSELATION_EVALUATION),
+		SHADER_STAGE_COMPUTE_BIT = (1 << SHADER_STAGE_COMPUTE),
+	};
+
+	struct ShaderStageSPIRVData {
+		ShaderStage shader_stage = SHADER_STAGE_MAX;
+		Vector<uint8_t> spirv;
+	};
+
+	/*********************/
+	/**** UNIFORM SET ****/
+	/*********************/
+
+	static const uint32_t MAX_UNIFORM_SETS = 16;
+
+	enum UniformType {
+		UNIFORM_TYPE_SAMPLER, // For sampling only (sampler GLSL type).
+		UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, // For sampling only, but includes a texture, (samplerXX GLSL type), first a sampler then a texture.
+		UNIFORM_TYPE_TEXTURE, // Only texture, (textureXX GLSL type).
+		UNIFORM_TYPE_IMAGE, // Storage image (imageXX GLSL type), for compute mostly.
+		UNIFORM_TYPE_TEXTURE_BUFFER, // Buffer texture (or TBO, textureBuffer type).
+		UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER, // Buffer texture with a sampler(or TBO, samplerBuffer type).
+		UNIFORM_TYPE_IMAGE_BUFFER, // Texel buffer, (imageBuffer type), for compute mostly.
+		UNIFORM_TYPE_UNIFORM_BUFFER, // Regular uniform buffer (or UBO).
+		UNIFORM_TYPE_STORAGE_BUFFER, // Storage buffer ("buffer" qualifier) like UBO, but supports storage, for compute mostly.
+		UNIFORM_TYPE_INPUT_ATTACHMENT, // Used for sub-pass read/write, for mobile mostly.
+		UNIFORM_TYPE_MAX
+	};
+
+	/******************/
+	/**** PIPELINE ****/
+	/******************/
+
+	enum PipelineSpecializationConstantType {
+		PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL,
+		PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT,
+		PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT,
+	};
+
+	struct PipelineSpecializationConstant {
+		PipelineSpecializationConstantType type = {};
+		uint32_t constant_id = 0xffffffff;
+		union {
+			uint32_t int_value = 0;
+			float float_value;
+			bool bool_value;
+		};
+	};
+
+	/*******************/
+	/**** RENDERING ****/
+	/*******************/
+
+	// ----- PIPELINE -----
+
+	enum RenderPrimitive {
+		RENDER_PRIMITIVE_POINTS,
+		RENDER_PRIMITIVE_LINES,
+		RENDER_PRIMITIVE_LINES_WITH_ADJACENCY,
+		RENDER_PRIMITIVE_LINESTRIPS,
+		RENDER_PRIMITIVE_LINESTRIPS_WITH_ADJACENCY,
+		RENDER_PRIMITIVE_TRIANGLES,
+		RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY,
+		RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+		RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_AJACENCY,
+		RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX,
+		RENDER_PRIMITIVE_TESSELATION_PATCH,
+		RENDER_PRIMITIVE_MAX
+	};
+
+	enum PolygonCullMode {
+		POLYGON_CULL_DISABLED,
+		POLYGON_CULL_FRONT,
+		POLYGON_CULL_BACK,
+		POLYGON_CULL_MAX
+	};
+
+	enum PolygonFrontFace {
+		POLYGON_FRONT_FACE_CLOCKWISE,
+		POLYGON_FRONT_FACE_COUNTER_CLOCKWISE,
+	};
+
+	enum StencilOperation {
+		STENCIL_OP_KEEP,
+		STENCIL_OP_ZERO,
+		STENCIL_OP_REPLACE,
+		STENCIL_OP_INCREMENT_AND_CLAMP,
+		STENCIL_OP_DECREMENT_AND_CLAMP,
+		STENCIL_OP_INVERT,
+		STENCIL_OP_INCREMENT_AND_WRAP,
+		STENCIL_OP_DECREMENT_AND_WRAP,
+		STENCIL_OP_MAX
+	};
+
+	enum LogicOperation {
+		LOGIC_OP_CLEAR,
+		LOGIC_OP_AND,
+		LOGIC_OP_AND_REVERSE,
+		LOGIC_OP_COPY,
+		LOGIC_OP_AND_INVERTED,
+		LOGIC_OP_NO_OP,
+		LOGIC_OP_XOR,
+		LOGIC_OP_OR,
+		LOGIC_OP_NOR,
+		LOGIC_OP_EQUIVALENT,
+		LOGIC_OP_INVERT,
+		LOGIC_OP_OR_REVERSE,
+		LOGIC_OP_COPY_INVERTED,
+		LOGIC_OP_OR_INVERTED,
+		LOGIC_OP_NAND,
+		LOGIC_OP_SET,
+		LOGIC_OP_MAX
+	};
+
+	enum BlendFactor {
+		BLEND_FACTOR_ZERO,
+		BLEND_FACTOR_ONE,
+		BLEND_FACTOR_SRC_COLOR,
+		BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
+		BLEND_FACTOR_DST_COLOR,
+		BLEND_FACTOR_ONE_MINUS_DST_COLOR,
+		BLEND_FACTOR_SRC_ALPHA,
+		BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+		BLEND_FACTOR_DST_ALPHA,
+		BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
+		BLEND_FACTOR_CONSTANT_COLOR,
+		BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
+		BLEND_FACTOR_CONSTANT_ALPHA,
+		BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
+		BLEND_FACTOR_SRC_ALPHA_SATURATE,
+		BLEND_FACTOR_SRC1_COLOR,
+		BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
+		BLEND_FACTOR_SRC1_ALPHA,
+		BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
+		BLEND_FACTOR_MAX
+	};
+
+	enum BlendOperation {
+		BLEND_OP_ADD,
+		BLEND_OP_SUBTRACT,
+		BLEND_OP_REVERSE_SUBTRACT,
+		BLEND_OP_MINIMUM,
+		BLEND_OP_MAXIMUM, // Yes, this one is an actual operator.
+		BLEND_OP_MAX
+	};
+
+	struct PipelineRasterizationState {
+		bool enable_depth_clamp = false;
+		bool discard_primitives = false;
+		bool wireframe = false;
+		PolygonCullMode cull_mode = POLYGON_CULL_DISABLED;
+		PolygonFrontFace front_face = POLYGON_FRONT_FACE_CLOCKWISE;
+		bool depth_bias_enabled = false;
+		float depth_bias_constant_factor = 0.0f;
+		float depth_bias_clamp = 0.0f;
+		float depth_bias_slope_factor = 0.0f;
+		float line_width = 1.0f;
+		uint32_t patch_control_points = 1;
+	};
+
+	struct PipelineMultisampleState {
+		TextureSamples sample_count = TEXTURE_SAMPLES_1;
+		bool enable_sample_shading = false;
+		float min_sample_shading = 0.0f;
+		Vector<uint32_t> sample_mask;
+		bool enable_alpha_to_coverage = false;
+		bool enable_alpha_to_one = false;
+	};
+
+	struct PipelineDepthStencilState {
+		bool enable_depth_test = false;
+		bool enable_depth_write = false;
+		CompareOperator depth_compare_operator = COMPARE_OP_ALWAYS;
+		bool enable_depth_range = false;
+		float depth_range_min = 0;
+		float depth_range_max = 0;
+		bool enable_stencil = false;
+
+		struct StencilOperationState {
+			StencilOperation fail = STENCIL_OP_ZERO;
+			StencilOperation pass = STENCIL_OP_ZERO;
+			StencilOperation depth_fail = STENCIL_OP_ZERO;
+			CompareOperator compare = COMPARE_OP_ALWAYS;
+			uint32_t compare_mask = 0;
+			uint32_t write_mask = 0;
+			uint32_t reference = 0;
+		};
+
+		StencilOperationState front_op;
+		StencilOperationState back_op;
+	};
+
+	struct PipelineColorBlendState {
+		bool enable_logic_op = false;
+		LogicOperation logic_op = LOGIC_OP_CLEAR;
+
+		struct Attachment {
+			bool enable_blend = false;
+			BlendFactor src_color_blend_factor = BLEND_FACTOR_ZERO;
+			BlendFactor dst_color_blend_factor = BLEND_FACTOR_ZERO;
+			BlendOperation color_blend_op = BLEND_OP_ADD;
+			BlendFactor src_alpha_blend_factor = BLEND_FACTOR_ZERO;
+			BlendFactor dst_alpha_blend_factor = BLEND_FACTOR_ZERO;
+			BlendOperation alpha_blend_op = BLEND_OP_ADD;
+			bool write_r = true;
+			bool write_g = true;
+			bool write_b = true;
+			bool write_a = true;
+		};
+
+		static PipelineColorBlendState create_disabled(int p_attachments = 1) {
+			PipelineColorBlendState bs;
+			for (int i = 0; i < p_attachments; i++) {
+				bs.attachments.push_back(Attachment());
+			}
+			return bs;
+		}
+
+		static PipelineColorBlendState create_blend(int p_attachments = 1) {
+			PipelineColorBlendState bs;
+			for (int i = 0; i < p_attachments; i++) {
+				Attachment ba;
+				ba.enable_blend = true;
+				ba.src_color_blend_factor = BLEND_FACTOR_SRC_ALPHA;
+				ba.dst_color_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+				ba.src_alpha_blend_factor = BLEND_FACTOR_SRC_ALPHA;
+				ba.dst_alpha_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+				bs.attachments.push_back(ba);
+			}
+			return bs;
+		}
+
+		Vector<Attachment> attachments; // One per render target texture.
+		Color blend_constant;
+	};
+
+	enum PipelineDynamicStateFlags {
+		DYNAMIC_STATE_LINE_WIDTH = (1 << 0),
+		DYNAMIC_STATE_DEPTH_BIAS = (1 << 1),
+		DYNAMIC_STATE_BLEND_CONSTANTS = (1 << 2),
+		DYNAMIC_STATE_DEPTH_BOUNDS = (1 << 3),
+		DYNAMIC_STATE_STENCIL_COMPARE_MASK = (1 << 4),
+		DYNAMIC_STATE_STENCIL_WRITE_MASK = (1 << 5),
+		DYNAMIC_STATE_STENCIL_REFERENCE = (1 << 6),
+	};
+
+	/**************/
+	/**** MISC ****/
+	/**************/
+
+	// This enum matches VkPhysicalDeviceType (except for `DEVICE_TYPE_MAX`).
+	// Unlike VkPhysicalDeviceType, DeviceType is exposed to the scripting API.
+	enum DeviceType {
+		DEVICE_TYPE_OTHER,
+		DEVICE_TYPE_INTEGRATED_GPU,
+		DEVICE_TYPE_DISCRETE_GPU,
+		DEVICE_TYPE_VIRTUAL_GPU,
+		DEVICE_TYPE_CPU,
+		DEVICE_TYPE_MAX
+	};
+
+	// Defined in an API-agnostic way.
+	// Some may not make sense for the underlying API; in that case, 0 is returned.
+	enum DriverResource {
+		DRIVER_RESOURCE_LOGICAL_DEVICE,
+		DRIVER_RESOURCE_PHYSICAL_DEVICE,
+		DRIVER_RESOURCE_TOPMOST_OBJECT,
+		DRIVER_RESOURCE_COMMAND_QUEUE,
+		DRIVER_RESOURCE_QUEUE_FAMILY,
+		DRIVER_RESOURCE_TEXTURE,
+		DRIVER_RESOURCE_TEXTURE_VIEW,
+		DRIVER_RESOURCE_TEXTURE_DATA_FORMAT,
+		DRIVER_RESOURCE_SAMPLER,
+		DRIVER_RESOURCE_UNIFORM_SET,
+		DRIVER_RESOURCE_BUFFER,
+		DRIVER_RESOURCE_COMPUTE_PIPELINE,
+		DRIVER_RESOURCE_RENDER_PIPELINE,
+#ifndef DISABLE_DEPRECATED
+		DRIVER_RESOURCE_VULKAN_DEVICE = DRIVER_RESOURCE_LOGICAL_DEVICE,
+		DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE = DRIVER_RESOURCE_PHYSICAL_DEVICE,
+		DRIVER_RESOURCE_VULKAN_INSTANCE = DRIVER_RESOURCE_TOPMOST_OBJECT,
+		DRIVER_RESOURCE_VULKAN_QUEUE = DRIVER_RESOURCE_COMMAND_QUEUE,
+		DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX = DRIVER_RESOURCE_QUEUE_FAMILY,
+		DRIVER_RESOURCE_VULKAN_IMAGE = DRIVER_RESOURCE_TEXTURE,
+		DRIVER_RESOURCE_VULKAN_IMAGE_VIEW = DRIVER_RESOURCE_TEXTURE_VIEW,
+		DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT = DRIVER_RESOURCE_TEXTURE_DATA_FORMAT,
+		DRIVER_RESOURCE_VULKAN_SAMPLER = DRIVER_RESOURCE_SAMPLER,
+		DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET = DRIVER_RESOURCE_UNIFORM_SET,
+		DRIVER_RESOURCE_VULKAN_BUFFER = DRIVER_RESOURCE_BUFFER,
+		DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE = DRIVER_RESOURCE_COMPUTE_PIPELINE,
+		DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE = DRIVER_RESOURCE_RENDER_PIPELINE,
+#endif
+	};
+
+	enum Limit {
+		LIMIT_MAX_BOUND_UNIFORM_SETS,
+		LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS,
+		LIMIT_MAX_TEXTURES_PER_UNIFORM_SET,
+		LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET,
+		LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET,
+		LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET,
+		LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET,
+		LIMIT_MAX_DRAW_INDEXED_INDEX,
+		LIMIT_MAX_FRAMEBUFFER_HEIGHT,
+		LIMIT_MAX_FRAMEBUFFER_WIDTH,
+		LIMIT_MAX_TEXTURE_ARRAY_LAYERS,
+		LIMIT_MAX_TEXTURE_SIZE_1D,
+		LIMIT_MAX_TEXTURE_SIZE_2D,
+		LIMIT_MAX_TEXTURE_SIZE_3D,
+		LIMIT_MAX_TEXTURE_SIZE_CUBE,
+		LIMIT_MAX_TEXTURES_PER_SHADER_STAGE,
+		LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE,
+		LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE,
+		LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE,
+		LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE,
+		LIMIT_MAX_PUSH_CONSTANT_SIZE,
+		LIMIT_MAX_UNIFORM_BUFFER_SIZE,
+		LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET,
+		LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES,
+		LIMIT_MAX_VERTEX_INPUT_BINDINGS,
+		LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE,
+		LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
+		LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE,
+		LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X,
+		LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y,
+		LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z,
+		LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS,
+		LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X,
+		LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y,
+		LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z,
+		LIMIT_MAX_VIEWPORT_DIMENSIONS_X,
+		LIMIT_MAX_VIEWPORT_DIMENSIONS_Y,
+		LIMIT_SUBGROUP_SIZE,
+		LIMIT_SUBGROUP_MIN_SIZE,
+		LIMIT_SUBGROUP_MAX_SIZE,
+		LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
+		LIMIT_SUBGROUP_OPERATIONS,
+		LIMIT_VRS_TEXEL_WIDTH,
+		LIMIT_VRS_TEXEL_HEIGHT,
+	};
+
+	enum Features {
+		SUPPORTS_MULTIVIEW,
+		SUPPORTS_FSR_HALF_FLOAT,
+		SUPPORTS_ATTACHMENT_VRS,
+		// If not supported, a fragment shader with only side effets (i.e., writes  to buffers, but doesn't output to attachments), may be optimized down to no-op by the GPU driver.
+		SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS,
+	};
+
+	////////////////////////////////////////////
+	// PROTECTED STUFF
+	// Not exposed by RenderingDevice, but shared
+	// with RenderingDeviceDriver for convenience.
+	////////////////////////////////////////////
+protected:
+	/*****************/
+	/**** GENERIC ****/
+	/*****************/
+
+	static const char *const FORMAT_NAMES[DATA_FORMAT_MAX];
+
+	/*****************/
+	/**** TEXTURE ****/
+	/*****************/
+
+	static const uint32_t MAX_IMAGE_FORMAT_PLANES = 2;
+
+	static const uint32_t TEXTURE_SAMPLES_COUNT[TEXTURE_SAMPLES_MAX];
+
+	static uint32_t get_image_format_pixel_size(DataFormat p_format);
+	static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
+	uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
+	static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
+	static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr);
+	static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
+	static bool format_has_stencil(DataFormat p_format);
+	static uint32_t format_get_plane_count(DataFormat p_format);
+
+	/*****************/
+	/**** SAMPLER ****/
+	/*****************/
+
+	static const Color SAMPLER_BORDER_COLOR_VALUE[SAMPLER_BORDER_COLOR_MAX];
+
+	/**********************/
+	/**** VERTEX ARRAY ****/
+	/**********************/
+
+	static uint32_t get_format_vertex_size(DataFormat p_format);
+
+	/****************/
+	/**** SHADER ****/
+	/****************/
+
+	static const char *SHADER_STAGE_NAMES[SHADER_STAGE_MAX];
+
+	struct ShaderUniform {
+		UniformType type = UniformType::UNIFORM_TYPE_MAX;
+		bool writable = false;
+		uint32_t binding = 0;
+		BitField<ShaderStage> stages;
+		uint32_t length = 0; // Size of arrays (in total elements), or ubos (in bytes * total elements).
+
+		bool operator!=(const ShaderUniform &p_other) const {
+			return binding != p_other.binding || type != p_other.type || writable != p_other.writable || stages != p_other.stages || length != p_other.length;
+		}
+
+		bool operator<(const ShaderUniform &p_other) const {
+			if (binding != p_other.binding) {
+				return binding < p_other.binding;
+			}
+			if (type != p_other.type) {
+				return type < p_other.type;
+			}
+			if (writable != p_other.writable) {
+				return writable < p_other.writable;
+			}
+			if (stages != p_other.stages) {
+				return stages < p_other.stages;
+			}
+			if (length != p_other.length) {
+				return length < p_other.length;
+			}
+			return false;
+		}
+	};
+
+	struct ShaderSpecializationConstant : public PipelineSpecializationConstant {
+		BitField<ShaderStage> stages;
+	};
+
+	struct ShaderDescription {
+		uint64_t vertex_input_mask = 0;
+		uint32_t fragment_output_mask = 0;
+		bool is_compute = false;
+		uint32_t compute_local_size[3] = {};
+		uint32_t push_constant_size = 0;
+
+		Vector<Vector<ShaderUniform>> uniform_sets;
+		Vector<ShaderSpecializationConstant> specialization_constants;
+	};
+
+	struct ShaderReflection : public ShaderDescription {
+		BitField<ShaderStage> stages;
+		BitField<ShaderStage> push_constant_stages;
+	};
+};
+
+#endif // RENDERING_DEVICE_COMMONS_H

+ 380 - 0
servers/rendering/rendering_device_driver.cpp

@@ -0,0 +1,380 @@
+/**************************************************************************/
+/*  rendering_device_driver.cpp                                           */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_device_driver.h"
+
+#include "thirdparty/spirv-reflect/spirv_reflect.h"
+
+/****************/
+/**** SHADER ****/
+/****************/
+
+Error RenderingDeviceDriver::_reflect_spirv(VectorView<ShaderStageSPIRVData> p_spirv, ShaderReflection &r_reflection) {
+	r_reflection = {};
+
+	for (uint32_t i = 0; i < p_spirv.size(); i++) {
+		ShaderStage stage = p_spirv[i].shader_stage;
+		ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage);
+
+		if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) {
+			r_reflection.is_compute = true;
+			ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, FAILED,
+					"Compute shaders can only receive one stage, dedicated to compute.");
+		}
+		ERR_FAIL_COND_V_MSG(r_reflection.stages.has_flag(stage_flag), FAILED,
+				"Stage " + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + " submitted more than once.");
+
+		{
+			SpvReflectShaderModule module;
+			const uint8_t *spirv = p_spirv[i].spirv.ptr();
+			SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spirv.size(), spirv, &module);
+			ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+					"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed parsing shader.");
+
+			if (r_reflection.is_compute) {
+				r_reflection.compute_local_size[0] = module.entry_points->local_size.x;
+				r_reflection.compute_local_size[1] = module.entry_points->local_size.y;
+				r_reflection.compute_local_size[2] = module.entry_points->local_size.z;
+			}
+			uint32_t binding_count = 0;
+			result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr);
+			ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+					"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed enumerating descriptor bindings.");
+
+			if (binding_count > 0) {
+				// Parse bindings.
+
+				Vector<SpvReflectDescriptorBinding *> bindings;
+				bindings.resize(binding_count);
+				result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
+
+				ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings.");
+
+				for (uint32_t j = 0; j < binding_count; j++) {
+					const SpvReflectDescriptorBinding &binding = *bindings[j];
+
+					ShaderUniform uniform;
+
+					bool need_array_dimensions = false;
+					bool need_block_size = false;
+					bool may_be_writable = false;
+
+					switch (binding.descriptor_type) {
+						case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
+							uniform.type = UNIFORM_TYPE_SAMPLER;
+							need_array_dimensions = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
+							uniform.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+							need_array_dimensions = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
+							uniform.type = UNIFORM_TYPE_TEXTURE;
+							need_array_dimensions = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
+							uniform.type = UNIFORM_TYPE_IMAGE;
+							need_array_dimensions = true;
+							may_be_writable = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
+							uniform.type = UNIFORM_TYPE_TEXTURE_BUFFER;
+							need_array_dimensions = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
+							uniform.type = UNIFORM_TYPE_IMAGE_BUFFER;
+							need_array_dimensions = true;
+							may_be_writable = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
+							uniform.type = UNIFORM_TYPE_UNIFORM_BUFFER;
+							need_block_size = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
+							uniform.type = UNIFORM_TYPE_STORAGE_BUFFER;
+							need_block_size = true;
+							may_be_writable = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
+							ERR_PRINT("Dynamic uniform buffer not supported.");
+							continue;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
+							ERR_PRINT("Dynamic storage buffer not supported.");
+							continue;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
+							uniform.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
+							need_array_dimensions = true;
+						} break;
+						case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
+							ERR_PRINT("Acceleration structure not supported.");
+							continue;
+						} break;
+					}
+
+					if (need_array_dimensions) {
+						if (binding.array.dims_count == 0) {
+							uniform.length = 1;
+						} else {
+							for (uint32_t k = 0; k < binding.array.dims_count; k++) {
+								if (k == 0) {
+									uniform.length = binding.array.dims[0];
+								} else {
+									uniform.length *= binding.array.dims[k];
+								}
+							}
+						}
+
+					} else if (need_block_size) {
+						uniform.length = binding.block.size;
+					} else {
+						uniform.length = 0;
+					}
+
+					if (may_be_writable) {
+						uniform.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE);
+					} else {
+						uniform.writable = false;
+					}
+
+					uniform.binding = binding.binding;
+					uint32_t set = binding.set;
+
+					ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, FAILED,
+							"On shader stage '" + String(SHADER_STAGE_NAMES[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
+
+					if (set < (uint32_t)r_reflection.uniform_sets.size()) {
+						// Check if this already exists.
+						bool exists = false;
+						for (int k = 0; k < r_reflection.uniform_sets[set].size(); k++) {
+							if (r_reflection.uniform_sets[set][k].binding == uniform.binding) {
+								// Already exists, verify that it's the same type.
+								ERR_FAIL_COND_V_MSG(r_reflection.uniform_sets[set][k].type != uniform.type, FAILED,
+										"On shader stage '" + String(SHADER_STAGE_NAMES[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(uniform.binding) + " with different uniform type.");
+
+								// Also, verify that it's the same size.
+								ERR_FAIL_COND_V_MSG(r_reflection.uniform_sets[set][k].length != uniform.length, FAILED,
+										"On shader stage '" + String(SHADER_STAGE_NAMES[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(uniform.binding) + " with different uniform size.");
+
+								// Also, verify that it has the same writability.
+								ERR_FAIL_COND_V_MSG(r_reflection.uniform_sets[set][k].writable != uniform.writable, FAILED,
+										"On shader stage '" + String(SHADER_STAGE_NAMES[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(uniform.binding) + " with different writability.");
+
+								// Just append stage mask and return.
+								r_reflection.uniform_sets.write[set].write[k].stages.set_flag(stage_flag);
+								exists = true;
+								break;
+							}
+						}
+
+						if (exists) {
+							continue; // Merged.
+						}
+					}
+
+					uniform.stages.set_flag(stage_flag);
+
+					if (set >= (uint32_t)r_reflection.uniform_sets.size()) {
+						r_reflection.uniform_sets.resize(set + 1);
+					}
+
+					r_reflection.uniform_sets.write[set].push_back(uniform);
+				}
+			}
+
+			{
+				// Specialization constants.
+
+				uint32_t sc_count = 0;
+				result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
+				ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed enumerating specialization constants.");
+
+				if (sc_count) {
+					Vector<SpvReflectSpecializationConstant *> spec_constants;
+					spec_constants.resize(sc_count);
+
+					result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw());
+					ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+							"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed obtaining specialization constants.");
+
+					for (uint32_t j = 0; j < sc_count; j++) {
+						int32_t existing = -1;
+						ShaderSpecializationConstant sconst;
+						SpvReflectSpecializationConstant *spc = spec_constants[j];
+
+						sconst.constant_id = spc->constant_id;
+						sconst.int_value = 0; // Clear previous value JIC.
+						switch (spc->constant_type) {
+							case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
+								sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+								sconst.bool_value = spc->default_value.int_bool_value != 0;
+							} break;
+							case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
+								sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+								sconst.int_value = spc->default_value.int_bool_value;
+							} break;
+							case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
+								sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
+								sconst.float_value = spc->default_value.float_value;
+							} break;
+						}
+						sconst.stages.set_flag(stage_flag);
+
+						for (int k = 0; k < r_reflection.specialization_constants.size(); k++) {
+							if (r_reflection.specialization_constants[k].constant_id == sconst.constant_id) {
+								ERR_FAIL_COND_V_MSG(r_reflection.specialization_constants[k].type != sconst.type, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their types differ.");
+								ERR_FAIL_COND_V_MSG(r_reflection.specialization_constants[k].int_value != sconst.int_value, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their default values differ.");
+								existing = k;
+								break;
+							}
+						}
+
+						if (existing > 0) {
+							r_reflection.specialization_constants.write[existing].stages.set_flag(stage_flag);
+						} else {
+							r_reflection.specialization_constants.push_back(sconst);
+						}
+					}
+				}
+			}
+
+			if (stage == SHADER_STAGE_VERTEX) {
+				uint32_t iv_count = 0;
+				result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
+				ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed enumerating input variables.");
+
+				if (iv_count) {
+					Vector<SpvReflectInterfaceVariable *> input_vars;
+					input_vars.resize(iv_count);
+
+					result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw());
+					ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+							"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed obtaining input variables.");
+
+					for (uint32_t j = 0; j < iv_count; j++) {
+						if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
+							r_reflection.vertex_input_mask |= (((uint64_t)1) << input_vars[j]->location);
+						}
+					}
+				}
+			}
+
+			if (stage == SHADER_STAGE_FRAGMENT) {
+				uint32_t ov_count = 0;
+				result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr);
+				ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed enumerating output variables.");
+
+				if (ov_count) {
+					Vector<SpvReflectInterfaceVariable *> output_vars;
+					output_vars.resize(ov_count);
+
+					result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
+					ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+							"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed obtaining output variables.");
+
+					for (uint32_t j = 0; j < ov_count; j++) {
+						const SpvReflectInterfaceVariable *refvar = output_vars[j];
+						if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) {
+							r_reflection.fragment_output_mask |= 1 << refvar->location;
+						}
+					}
+				}
+			}
+
+			uint32_t pc_count = 0;
+			result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr);
+			ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+					"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed enumerating push constants.");
+
+			if (pc_count) {
+				ERR_FAIL_COND_V_MSG(pc_count > 1, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
+
+				Vector<SpvReflectBlockVariable *> pconstants;
+				pconstants.resize(pc_count);
+				result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
+				ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "' failed obtaining push constants.");
+#if 0
+				if (pconstants[0] == nullptr) {
+					Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
+					f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
+				}
+#endif
+
+				ERR_FAIL_COND_V_MSG(r_reflection.push_constant_size && r_reflection.push_constant_size != pconstants[0]->size, FAILED,
+						"Reflection of SPIR-V shader stage '" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
+
+				r_reflection.push_constant_size = pconstants[0]->size;
+				r_reflection.push_constant_stages.set_flag(stage_flag);
+
+				//print_line("Stage: " + String(SHADER_STAGE_NAMES[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+			}
+
+			// Destroy the reflection data when no longer required.
+			spvReflectDestroyShaderModule(&module);
+		}
+
+		r_reflection.stages.set_flag(stage_flag);
+	}
+
+	return OK;
+}
+
+/**************/
+/**** MISC ****/
+/**************/
+
+uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) {
+	// Sensible canonical defaults.
+	switch (p_trait) {
+		case API_TRAIT_HONORS_PIPELINE_BARRIERS:
+			return 1;
+		case API_TRAIT_SHADER_CHANGE_INVALIDATION:
+			return SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS;
+		case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT:
+			return 1;
+		case API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP:
+			return 1;
+		case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR:
+			return 1;
+		default:
+			ERR_FAIL_V(0);
+	}
+}
+
+/******************/
+
+RenderingDeviceDriver::~RenderingDeviceDriver() {}

+ 687 - 0
servers/rendering/rendering_device_driver.h

@@ -0,0 +1,687 @@
+/**************************************************************************/
+/*  rendering_device_driver.h                                             */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_DEVICE_DRIVER_H
+#define RENDERING_DEVICE_DRIVER_H
+
+// ***********************************************************************************
+// RenderingDeviceDriver - Design principles
+// -----------------------------------------
+// - Very little validation is done, and normally only in dev or debug builds.
+// - Error reporting is generally simple: returning an id of 0 or a false boolean.
+// - Certain enums/constants/structs follow Vulkan values/layout. That makes things easier for RDDVulkan (it asserts compatibility).
+// - We allocate as little as possible in functions expected to be quick (a counterexample is loading/saving shaders) and use alloca() whenever suitable.
+// - We try to back opaque ids with the native ones or memory addresses.
+// - When using bookkeeping structures because the actual API id of a resource is not enough, we use a PagedAllocator.
+// - Every struct has default initializers.
+// - Using VectorView to take array-like arguments. Vector<uint8_t> is an exception (an indiom for "BLOB").
+// - If a driver needs some higher-level information (the kind of info RenderingDevice keeps), it shall store a copy of what it needs.
+//   There's no backwards communication from the driver to query data from RenderingDevice.
+// ***********************************************************************************
+
+#include "core/object/object.h"
+#include "core/variant/type_info.h"
+#include "servers/display_server.h"
+#include "servers/rendering/rendering_device_commons.h"
+
+#include <algorithm>
+
+class ApiContextRD;
+
+// This may one day be used in Godot for interoperability between C arrays, Vector and LocalVector.
+// (See https://github.com/godotengine/godot-proposals/issues/5144.)
+template <class T>
+class VectorView {
+	const T *_ptr = nullptr;
+	const uint32_t _size = 0;
+
+public:
+	const T &operator[](uint32_t p_index) {
+		DEV_ASSERT(p_index < _size);
+		return _ptr[p_index];
+	}
+
+	_ALWAYS_INLINE_ const T *ptr() const { return _ptr; }
+	_ALWAYS_INLINE_ uint32_t size() const { return _size; }
+
+	VectorView() = default;
+	VectorView(const T &p_ptr) :
+			// With this one you can pass a single element very conveniently!
+			_ptr(&p_ptr),
+			_size(1) {}
+	VectorView(const T *p_ptr, uint32_t p_size) :
+			_ptr(p_ptr), _size(p_size) {}
+	VectorView(const Vector<T> &p_lv) :
+			_ptr(p_lv.ptr()), _size(p_lv.size()) {}
+	VectorView(const LocalVector<T> &p_lv) :
+			_ptr(p_lv.ptr()), _size(p_lv.size()) {}
+};
+
+// These utilities help drivers avoid allocations.
+#define ALLOCA(m_size) ((m_size != 0) ? alloca(m_size) : nullptr)
+#define ALLOCA_ARRAY(m_type, m_count) ((m_type *)ALLOCA(sizeof(m_type) * (m_count)))
+#define ALLOCA_SINGLE(m_type) ALLOCA_ARRAY(m_type, 1)
+
+// This helps forwarding certain arrays to the API with confidence.
+#define ARRAYS_COMPATIBLE(m_type_a, m_type_b) (sizeof(m_type_a) == sizeof(m_type_b) && alignof(m_type_a) == alignof(m_type_b))
+// This is used when you also need to ensure structured types are compatible field-by-field.
+// TODO: The fieldwise check is unimplemented, but still this one is useful, as a strong annotation about the needs.
+#define ARRAYS_COMPATIBLE_FIELDWISE(m_type_a, m_type_b) ARRAYS_COMPATIBLE(m_type_a, m_type_b)
+// Another utility, to make it easy to compare members of different enums, which is not fine with some compilers.
+#define ENUM_MEMBERS_EQUAL(m_a, m_b) ((int64_t)m_a == (int64_t)m_b)
+
+// This helps using a single paged allocator for many resource types.
+template <class... RESOURCE_TYPES>
+struct VersatileResourceTemplate {
+	static constexpr size_t RESOURCE_SIZES[] = { sizeof(RESOURCE_TYPES)... };
+	static constexpr size_t MAX_RESOURCE_SIZE = std::max_element(RESOURCE_SIZES, RESOURCE_SIZES + sizeof...(RESOURCE_TYPES))[0];
+	uint8_t data[MAX_RESOURCE_SIZE];
+
+	template <class T>
+	static T *allocate(PagedAllocator<VersatileResourceTemplate> &p_allocator) {
+		T *obj = (T *)p_allocator.alloc();
+		*obj = T();
+		return obj;
+	}
+
+	template <class T>
+	static void free(PagedAllocator<VersatileResourceTemplate> &p_allocator, T *p_object) {
+		p_object->~T();
+		p_allocator.free((VersatileResourceTemplate *)p_object);
+	}
+};
+
+class RenderingDeviceDriver : public RenderingDeviceCommons {
+public:
+	struct ID {
+		size_t id = 0;
+		_ALWAYS_INLINE_ ID() = default;
+		_ALWAYS_INLINE_ ID(size_t p_id) :
+				id(p_id) {}
+	};
+
+#define DEFINE_ID(m_name)                                                                           \
+	struct m_name##ID : public ID {                                                                 \
+		_ALWAYS_INLINE_ operator bool() const { return id != 0; }                                   \
+		_ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) {                                 \
+			id = p_other.id;                                                                        \
+			return *this;                                                                           \
+		}                                                                                           \
+		_ALWAYS_INLINE_ bool operator<(const m_name##ID &p_other) const { return id < p_other.id; } \
+		_ALWAYS_INLINE_ m_name##ID(const m_name##ID &p_other) : ID(p_other.id) {}                   \
+		_ALWAYS_INLINE_ explicit m_name##ID(uint64_t p_int) : ID(p_int) {}                          \
+		_ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((size_t)p_ptr) {}                     \
+		_ALWAYS_INLINE_ m_name##ID() = default;                                                     \
+	};                                                                                              \
+	/* Ensure type-punnable to pointer. Makes some things easier.*/                                 \
+	static_assert(sizeof(m_name##ID) == sizeof(void *));
+
+	// Id types declared before anything else to prevent cyclic dependencies between the different concerns.
+	DEFINE_ID(Buffer);
+	DEFINE_ID(Texture);
+	DEFINE_ID(Sampler);
+	DEFINE_ID(VertexFormat);
+	DEFINE_ID(CommandPool);
+	DEFINE_ID(CommandBuffer);
+	DEFINE_ID(Framebuffer);
+	DEFINE_ID(Shader);
+	DEFINE_ID(UniformSet);
+	DEFINE_ID(Pipeline);
+	DEFINE_ID(RenderPass);
+	DEFINE_ID(QueryPool);
+
+	/****************/
+	/**** MEMORY ****/
+	/****************/
+
+	enum MemoryAllocationType {
+		MEMORY_ALLOCATION_TYPE_CPU, // For images, CPU allocation also means linear, GPU is tiling optimal.
+		MEMORY_ALLOCATION_TYPE_GPU,
+	};
+
+	/*****************/
+	/**** BUFFERS ****/
+	/*****************/
+
+	enum BufferUsageBits {
+		BUFFER_USAGE_TRANSFER_FROM_BIT = (1 << 0),
+		BUFFER_USAGE_TRANSFER_TO_BIT = (1 << 1),
+		BUFFER_USAGE_TEXEL_BIT = (1 << 2),
+		BUFFER_USAGE_UNIFORM_BIT = (1 << 4),
+		BUFFER_USAGE_STORAGE_BIT = (1 << 5),
+		BUFFER_USAGE_INDEX_BIT = (1 << 6),
+		BUFFER_USAGE_VERTEX_BIT = (1 << 7),
+		BUFFER_USAGE_INDIRECT_BIT = (1 << 8),
+	};
+
+	virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) = 0;
+	// Only for a buffer with BUFFER_USAGE_TEXEL_BIT.
+	virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) = 0;
+	virtual void buffer_free(BufferID p_buffer) = 0;
+	virtual uint64_t buffer_get_allocation_size(BufferID p_buffer) = 0;
+	virtual uint8_t *buffer_map(BufferID p_buffer) = 0;
+	virtual void buffer_unmap(BufferID p_buffer) = 0;
+
+	/*****************/
+	/**** TEXTURE ****/
+	/*****************/
+
+	struct TextureView {
+		DataFormat format = DATA_FORMAT_MAX;
+		TextureSwizzle swizzle_r = TEXTURE_SWIZZLE_R;
+		TextureSwizzle swizzle_g = TEXTURE_SWIZZLE_G;
+		TextureSwizzle swizzle_b = TEXTURE_SWIZZLE_B;
+		TextureSwizzle swizzle_a = TEXTURE_SWIZZLE_A;
+	};
+
+	enum TextureLayout {
+		TEXTURE_LAYOUT_UNDEFINED,
+		TEXTURE_LAYOUT_GENERAL,
+		TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+		TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+		TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+		TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+		TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		TEXTURE_LAYOUT_PREINITIALIZED,
+		TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL = 1000164003,
+	};
+
+	enum TextureAspect {
+		TEXTURE_ASPECT_COLOR = 0,
+		TEXTURE_ASPECT_DEPTH = 1,
+		TEXTURE_ASPECT_STENCIL = 2,
+		TEXTURE_ASPECT_MAX
+	};
+
+	enum TextureAspectBits {
+		TEXTURE_ASPECT_COLOR_BIT = (1 << TEXTURE_ASPECT_COLOR),
+		TEXTURE_ASPECT_DEPTH_BIT = (1 << TEXTURE_ASPECT_DEPTH),
+		TEXTURE_ASPECT_STENCIL_BIT = (1 << TEXTURE_ASPECT_STENCIL),
+	};
+
+	struct TextureSubresource {
+		TextureAspect aspect = TEXTURE_ASPECT_COLOR;
+		uint32_t layer = 0;
+		uint32_t mipmap = 0;
+	};
+
+	struct TextureSubresourceLayers {
+		BitField<TextureAspectBits> aspect;
+		uint32_t mipmap = 0;
+		uint32_t base_layer = 0;
+		uint32_t layer_count = 0;
+	};
+
+	struct TextureSubresourceRange {
+		BitField<TextureAspectBits> aspect;
+		uint32_t base_mipmap = 0;
+		uint32_t mipmap_count = 0;
+		uint32_t base_layer = 0;
+		uint32_t layer_count = 0;
+	};
+
+	struct TextureCopyableLayout {
+		uint64_t offset = 0;
+		uint64_t size = 0;
+		uint64_t row_pitch = 0;
+		uint64_t depth_pitch = 0;
+		uint64_t layer_pitch = 0;
+	};
+
+	virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) = 0;
+	virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) = 0;
+	// texture_create_shared_*() can only use original, non-view textures as original. RenderingDevice is responsible for ensuring that.
+	virtual TextureID texture_create_shared(TextureID p_original_texture, const TextureView &p_view) = 0;
+	virtual TextureID texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) = 0;
+	virtual void texture_free(TextureID p_texture) = 0;
+	virtual uint64_t texture_get_allocation_size(TextureID p_texture) = 0;
+	virtual void texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) = 0;
+	virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) = 0;
+	virtual void texture_unmap(TextureID p_texture) = 0;
+	virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) = 0;
+
+	/*****************/
+	/**** SAMPLER ****/
+	/*****************/
+
+	virtual SamplerID sampler_create(const SamplerState &p_state) = 0;
+	virtual void sampler_free(SamplerID p_sampler) = 0;
+	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) = 0;
+
+	/**********************/
+	/**** VERTEX ARRAY ****/
+	/**********************/
+
+	virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) = 0;
+	virtual void vertex_format_free(VertexFormatID p_vertex_format) = 0;
+
+	/******************/
+	/**** BARRIERS ****/
+	/******************/
+
+	enum PipelineStageBits {
+		PIPELINE_STAGE_TOP_OF_PIPE_BIT = (1 << 0),
+		PIPELINE_STAGE_DRAW_INDIRECT_BIT = (1 << 1),
+		PIPELINE_STAGE_VERTEX_INPUT_BIT = (1 << 2),
+		PIPELINE_STAGE_VERTEX_SHADER_BIT = (1 << 3),
+		PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = (1 << 4),
+		PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = (1 << 5),
+		PIPELINE_STAGE_GEOMETRY_SHADER_BIT = (1 << 6),
+		PIPELINE_STAGE_FRAGMENT_SHADER_BIT = (1 << 7),
+		PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = (1 << 8),
+		PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = (1 << 9),
+		PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = (1 << 10),
+		PIPELINE_STAGE_COMPUTE_SHADER_BIT = (1 << 11),
+		PIPELINE_STAGE_TRANSFER_BIT = (1 << 12),
+		PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = (1 << 13),
+		PIPELINE_STAGE_ALL_GRAPHICS_BIT = (1 << 15),
+		PIPELINE_STAGE_ALL_COMMANDS_BIT = (1 << 16),
+	};
+
+	enum BarrierAccessBits {
+		BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT = (1 << 0),
+		BARRIER_ACCESS_INDEX_READ_BIT = (1 << 1),
+		BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = (1 << 2),
+		BARRIER_ACCESS_UNIFORM_READ_BIT = (1 << 3),
+		BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT = (1 << 4),
+		BARRIER_ACCESS_SHADER_READ_BIT = (1 << 5),
+		BARRIER_ACCESS_SHADER_WRITE_BIT = (1 << 6),
+		BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT = (1 << 7),
+		BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = (1 << 8),
+		BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = (1 << 9),
+		BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = (1 << 10),
+		BARRIER_ACCESS_TRANSFER_READ_BIT = (1 << 11),
+		BARRIER_ACCESS_TRANSFER_WRITE_BIT = (1 << 12),
+		BARRIER_ACCESS_HOST_READ_BIT = (1 << 13),
+		BARRIER_ACCESS_HOST_WRITE_BIT = (1 << 14),
+		BARRIER_ACCESS_MEMORY_READ_BIT = (1 << 15),
+		BARRIER_ACCESS_MEMORY_WRITE_BIT = (1 << 16),
+		BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT = (1 << 23),
+	};
+
+	struct MemoryBarrier {
+		BitField<BarrierAccessBits> src_access;
+		BitField<BarrierAccessBits> dst_access;
+	};
+
+	struct BufferBarrier {
+		BufferID buffer;
+		BitField<BarrierAccessBits> src_access;
+		BitField<BarrierAccessBits> dst_access;
+		uint64_t offset = 0;
+		uint64_t size = 0;
+	};
+
+	struct TextureBarrier {
+		TextureID texture;
+		BitField<BarrierAccessBits> src_access;
+		BitField<BarrierAccessBits> dst_access;
+		TextureLayout prev_layout = TEXTURE_LAYOUT_UNDEFINED;
+		TextureLayout next_layout = TEXTURE_LAYOUT_UNDEFINED;
+		TextureSubresourceRange subresources;
+	};
+
+	virtual void command_pipeline_barrier(
+			CommandBufferID p_cmd_buffer,
+			BitField<PipelineStageBits> p_src_stages,
+			BitField<PipelineStageBits> p_dst_stages,
+			VectorView<MemoryBarrier> p_memory_barriers,
+			VectorView<BufferBarrier> p_buffer_barriers,
+			VectorView<TextureBarrier> p_texture_barriers) = 0;
+
+	/*************************/
+	/**** COMMAND BUFFERS ****/
+	/*************************/
+
+	// ----- POOL -----
+
+	enum CommandBufferType {
+		COMMAND_BUFFER_TYPE_PRIMARY,
+		COMMAND_BUFFER_TYPE_SECONDARY,
+	};
+
+	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) = 0;
+	virtual void command_pool_free(CommandPoolID p_cmd_pool) = 0;
+
+	// ----- BUFFER -----
+
+	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) = 0;
+	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) = 0;
+	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) = 0;
+	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) = 0;
+	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) = 0;
+
+	/*********************/
+	/**** FRAMEBUFFER ****/
+	/*********************/
+
+	virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) = 0;
+	virtual void framebuffer_free(FramebufferID p_framebuffer) = 0;
+
+	/****************/
+	/**** SHADER ****/
+	/****************/
+
+	virtual String shader_get_binary_cache_key() = 0;
+	virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) = 0;
+	virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) = 0;
+	// Only meaningful if API_TRAIT_SHADER_CHANGE_INVALIDATION is SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH.
+	virtual uint32_t shader_get_layout_hash(ShaderID p_shader) { return 0; }
+	virtual void shader_free(ShaderID p_shader) = 0;
+
+protected:
+	// An optional service to implementations.
+	Error _reflect_spirv(VectorView<ShaderStageSPIRVData> p_spirv, ShaderReflection &r_reflection);
+
+public:
+	/*********************/
+	/**** UNIFORM SET ****/
+	/*********************/
+
+	struct BoundUniform {
+		UniformType type = UNIFORM_TYPE_MAX;
+		uint32_t binding = 0xffffffff; // Binding index as specified in shader.
+		LocalVector<ID> ids;
+	};
+
+	virtual UniformSetID uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index) = 0;
+	virtual void uniform_set_free(UniformSetID p_uniform_set) = 0;
+
+	// ----- COMMANDS -----
+
+	virtual void command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) = 0;
+
+	/******************/
+	/**** TRANSFER ****/
+	/******************/
+
+	struct BufferCopyRegion {
+		uint64_t src_offset = 0;
+		uint64_t dst_offset = 0;
+		uint64_t size = 0;
+	};
+
+	struct TextureCopyRegion {
+		TextureSubresourceLayers src_subresources;
+		Vector3i src_offset;
+		TextureSubresourceLayers dst_subresources;
+		Vector3i dst_offset;
+		Vector3i size;
+	};
+
+	struct BufferTextureCopyRegion {
+		uint64_t buffer_offset = 0;
+		TextureSubresourceLayers texture_subresources;
+		Vector3i texture_offset;
+		Vector3i texture_region_size;
+	};
+
+	virtual void command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) = 0;
+	virtual void command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) = 0;
+
+	virtual void command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) = 0;
+	virtual void command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) = 0;
+	virtual void command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) = 0;
+
+	virtual void command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) = 0;
+	virtual void command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) = 0;
+
+	/******************/
+	/**** PIPELINE ****/
+	/******************/
+
+	virtual void pipeline_free(PipelineID p_pipeline) = 0;
+
+	// ----- BINDING -----
+
+	virtual void command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_first_index, VectorView<uint32_t> p_data) = 0;
+
+	// ----- CACHE -----
+
+	virtual bool pipeline_cache_create(const Vector<uint8_t> &p_data) = 0;
+	virtual void pipeline_cache_free() = 0;
+	virtual size_t pipeline_cache_query_size() = 0;
+	virtual Vector<uint8_t> pipeline_cache_serialize() = 0;
+
+	/*******************/
+	/**** RENDERING ****/
+	/*******************/
+
+	// ----- SUBPASS -----
+
+	enum AttachmentLoadOp {
+		ATTACHMENT_LOAD_OP_LOAD = 0,
+		ATTACHMENT_LOAD_OP_CLEAR = 1,
+		ATTACHMENT_LOAD_OP_DONT_CARE = 2,
+	};
+
+	enum AttachmentStoreOp {
+		ATTACHMENT_STORE_OP_STORE = 0,
+		ATTACHMENT_STORE_OP_DONT_CARE = 1,
+	};
+
+	struct Attachment {
+		DataFormat format = DATA_FORMAT_MAX;
+		TextureSamples samples = TEXTURE_SAMPLES_MAX;
+		AttachmentLoadOp load_op = ATTACHMENT_LOAD_OP_DONT_CARE;
+		AttachmentStoreOp store_op = ATTACHMENT_STORE_OP_DONT_CARE;
+		AttachmentLoadOp stencil_load_op = ATTACHMENT_LOAD_OP_DONT_CARE;
+		AttachmentStoreOp stencil_store_op = ATTACHMENT_STORE_OP_DONT_CARE;
+		TextureLayout initial_layout = TEXTURE_LAYOUT_UNDEFINED;
+		TextureLayout final_layout = TEXTURE_LAYOUT_UNDEFINED;
+	};
+
+	struct AttachmentReference {
+		static const uint32_t UNUSED = 0xffffffff;
+		uint32_t attachment = UNUSED;
+		TextureLayout layout = TEXTURE_LAYOUT_UNDEFINED;
+		BitField<TextureAspectBits> aspect;
+	};
+
+	struct Subpass {
+		LocalVector<AttachmentReference> input_references;
+		LocalVector<AttachmentReference> color_references;
+		AttachmentReference depth_stencil_reference;
+		LocalVector<AttachmentReference> resolve_references;
+		LocalVector<uint32_t> preserve_attachments;
+		AttachmentReference vrs_reference;
+	};
+
+	struct SubpassDependency {
+		uint32_t src_subpass = 0xffffffff;
+		uint32_t dst_subpass = 0xffffffff;
+		BitField<PipelineStageBits> src_stages;
+		BitField<PipelineStageBits> dst_stages;
+		BitField<BarrierAccessBits> src_access;
+		BitField<BarrierAccessBits> dst_access;
+	};
+
+	virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) = 0;
+	virtual void render_pass_free(RenderPassID p_render_pass) = 0;
+
+	// ----- COMMANDS -----
+
+	union RenderPassClearValue {
+		Color color = {};
+		struct {
+			float depth;
+			uint32_t stencil;
+		};
+	};
+
+	struct AttachmentClear {
+		BitField<TextureAspectBits> aspect;
+		uint32_t color_attachment = 0xffffffff;
+		RenderPassClearValue value;
+	};
+
+	virtual void command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) = 0;
+	virtual void command_end_render_pass(CommandBufferID p_cmd_buffer) = 0;
+	virtual void command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) = 0;
+	virtual void command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) = 0;
+	virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) = 0;
+	virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) = 0;
+
+	// Binding.
+	virtual void command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) = 0;
+	virtual void command_bind_render_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) = 0;
+
+	// Drawing.
+	virtual void command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) = 0;
+	virtual void command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) = 0;
+	virtual void command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) = 0;
+	virtual void command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) = 0;
+	virtual void command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) = 0;
+	virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) = 0;
+
+	// Buffer binding.
+	virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) = 0;
+	virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) = 0;
+
+	// Dynamic state.
+	virtual void command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) = 0;
+	virtual void command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) = 0;
+
+	// ----- PIPELINE -----
+
+	virtual PipelineID render_pipeline_create(
+			ShaderID p_shader,
+			VertexFormatID p_vertex_format,
+			RenderPrimitive p_render_primitive,
+			PipelineRasterizationState p_rasterization_state,
+			PipelineMultisampleState p_multisample_state,
+			PipelineDepthStencilState p_depth_stencil_state,
+			PipelineColorBlendState p_blend_state,
+			VectorView<int32_t> p_color_attachments,
+			BitField<PipelineDynamicStateFlags> p_dynamic_state,
+			RenderPassID p_render_pass,
+			uint32_t p_render_subpass,
+			VectorView<PipelineSpecializationConstant> p_specialization_constants) = 0;
+
+	/*****************/
+	/**** COMPUTE ****/
+	/*****************/
+
+	// ----- COMMANDS -----
+
+	// Binding.
+	virtual void command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) = 0;
+	virtual void command_bind_compute_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) = 0;
+
+	// Dispatching.
+	virtual void command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
+	virtual void command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) = 0;
+
+	// ----- PIPELINE -----
+
+	virtual PipelineID compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) = 0;
+
+	/*****************/
+	/**** QUERIES ****/
+	/*****************/
+
+	// ----- TIMESTAMP -----
+
+	// Basic.
+	virtual QueryPoolID timestamp_query_pool_create(uint32_t p_query_count) = 0;
+	virtual void timestamp_query_pool_free(QueryPoolID p_pool_id) = 0;
+	virtual void timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) = 0;
+	virtual uint64_t timestamp_query_result_to_time(uint64_t p_result) = 0;
+
+	// Commands.
+	virtual void command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) = 0;
+	virtual void command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) = 0;
+
+	/****************/
+	/**** SCREEN ****/
+	/****************/
+
+	virtual DataFormat screen_get_format() = 0;
+
+	/********************/
+	/**** SUBMISSION ****/
+	/********************/
+
+	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) = 0;
+	virtual void end_segment() = 0;
+
+	/**************/
+	/**** MISC ****/
+	/**************/
+
+	enum ObjectType {
+		OBJECT_TYPE_TEXTURE,
+		OBJECT_TYPE_SAMPLER,
+		OBJECT_TYPE_BUFFER,
+		OBJECT_TYPE_SHADER,
+		OBJECT_TYPE_UNIFORM_SET,
+		OBJECT_TYPE_PIPELINE,
+	};
+
+	struct MultiviewCapabilities {
+		bool is_supported = false;
+		bool geometry_shader_is_supported = false;
+		bool tessellation_shader_is_supported = false;
+		uint32_t max_view_count = 0;
+		uint32_t max_instance_count = 0;
+	};
+
+	enum ApiTrait {
+		API_TRAIT_HONORS_PIPELINE_BARRIERS,
+		API_TRAIT_SHADER_CHANGE_INVALIDATION,
+		API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT,
+		API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP,
+		API_TRAIT_SECONDARY_VIEWPORT_SCISSOR,
+	};
+	enum ShaderChangeInvalidation {
+		SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS,
+		// What Vulkan does.
+		SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE,
+		// What D3D12 does.
+		SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH,
+	};
+
+	virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) = 0;
+	virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) = 0;
+	virtual uint64_t get_total_memory_used() = 0;
+	virtual uint64_t limit_get(Limit p_limit) = 0;
+	virtual uint64_t api_trait_get(ApiTrait p_trait);
+	virtual bool has_feature(Features p_feature) = 0;
+	virtual const MultiviewCapabilities &get_multiview_capabilities() = 0;
+
+	/******************/
+
+	virtual ~RenderingDeviceDriver();
+};
+
+using RDD = RenderingDeviceDriver;
+
+#endif // RENDERING_DEVICE_DRIVER_H

+ 10 - 1
thirdparty/README.md

@@ -132,18 +132,27 @@ Files extracted from upstream source:
 - `include/D3D12MemAlloc.h`
 - `LICENSE.txt`, `NOTICES.txt`
 
+Important: Some files have Godot-made changes for use with MinGW.
+They are marked with `/* GODOT start */` and `/* GODOT end */`
+comments.
+
 
 ## directx_headers
 
 - Upstream: https://github.com/microsoft/DirectX-Headers
-- Version: 1.606.3 (fd329244e62201bf959331d28514928fc1d45005, 2022)
+- Version: 1.611.1 (48f23952bc08a6dce0727339c07cedbc4797356c, 2023)
 - License: MIT
 
 Files extracted from upstream source:
 
 - `include/directx/*.h`
+- `include/dxguids/*.h`
 - `LICENSE`
 
+Important: Some files have Godot-made changes for use with MinGW.
+They are marked with `/* GODOT start */` and `/* GODOT end */`
+comments.
+
 
 ## doctest
 

+ 24 - 0
thirdparty/d3d12ma/D3D12MemAlloc.cpp

@@ -33,6 +33,14 @@
     #include <shared_mutex>
 #endif
 
+/* GODOT start */
+#if !defined(_MSC_VER)
+#include <guiddef.h>
+
+#include <dxguids.h>
+#endif
+/* GODOT end */
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -8178,7 +8186,15 @@ HRESULT AllocatorPimpl::UpdateD3D12Budget()
 
 D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const
 {
+/* GODOT start */
+#if defined(_MSC_VER) || !defined(_WIN32)
     return m_Device->GetResourceAllocationInfo(0, 1, &resourceDesc);
+#else
+    D3D12_RESOURCE_ALLOCATION_INFO ret;
+    m_Device->GetResourceAllocationInfo(&ret, 0, 1, &resourceDesc);
+    return ret;
+#endif
+/* GODOT end */
 }
 
 #ifdef __ID3D12Device8_INTERFACE_DEFINED__
@@ -8186,7 +8202,15 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(c
 {
     D3D12MA_ASSERT(m_Device8 != NULL);
     D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused;
+/* GODOT start */
+#if defined(_MSC_VER) || !defined(_WIN32)
     return m_Device8->GetResourceAllocationInfo2(0, 1, &resourceDesc, &info1Unused);
+#else
+    D3D12_RESOURCE_ALLOCATION_INFO ret;
+    m_Device8->GetResourceAllocationInfo2(&ret, 0, 1, &resourceDesc, &info1Unused);
+    return ret;
+#endif
+/* GODOT end */
 }
 #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
 

+ 0 - 5459
thirdparty/directx_headers/d3dx12.h

@@ -1,5459 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License (MIT).
-//
-//*********************************************************
-
-#ifndef __D3DX12_H__
-#define __D3DX12_H__
-
-#include "d3d12.h"
-
-#if defined( __cplusplus )
-
-struct CD3DX12_DEFAULT {};
-extern const DECLSPEC_SELECTANY CD3DX12_DEFAULT D3D12_DEFAULT;
-
-//------------------------------------------------------------------------------------------------
-inline bool operator==( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept
-{
-    return l.TopLeftX == r.TopLeftX && l.TopLeftY == r.TopLeftY && l.Width == r.Width &&
-        l.Height == r.Height && l.MinDepth == r.MinDepth && l.MaxDepth == r.MaxDepth;
-}
-
-//------------------------------------------------------------------------------------------------
-inline bool operator!=( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RECT : public D3D12_RECT
-{
-    CD3DX12_RECT() = default;
-    explicit CD3DX12_RECT( const D3D12_RECT& o ) noexcept :
-        D3D12_RECT( o )
-    {}
-    explicit CD3DX12_RECT(
-        LONG Left,
-        LONG Top,
-        LONG Right,
-        LONG Bottom ) noexcept
-    {
-        left = Left;
-        top = Top;
-        right = Right;
-        bottom = Bottom;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_VIEWPORT : public D3D12_VIEWPORT
-{
-    CD3DX12_VIEWPORT() = default;
-    explicit CD3DX12_VIEWPORT( const D3D12_VIEWPORT& o ) noexcept :
-        D3D12_VIEWPORT( o )
-    {}
-    explicit CD3DX12_VIEWPORT(
-        FLOAT topLeftX,
-        FLOAT topLeftY,
-        FLOAT width,
-        FLOAT height,
-        FLOAT minDepth = D3D12_MIN_DEPTH,
-        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept
-    {
-        TopLeftX = topLeftX;
-        TopLeftY = topLeftY;
-        Width = width;
-        Height = height;
-        MinDepth = minDepth;
-        MaxDepth = maxDepth;
-    }
-    explicit CD3DX12_VIEWPORT(
-        _In_ ID3D12Resource* pResource,
-        UINT mipSlice = 0,
-        FLOAT topLeftX = 0.0f,
-        FLOAT topLeftY = 0.0f,
-        FLOAT minDepth = D3D12_MIN_DEPTH,
-        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept
-    {
-        const auto Desc = pResource->GetDesc();
-        const UINT64 SubresourceWidth = Desc.Width >> mipSlice;
-        const UINT64 SubresourceHeight = Desc.Height >> mipSlice;
-        switch (Desc.Dimension)
-        {
-        case D3D12_RESOURCE_DIMENSION_BUFFER:
-            TopLeftX = topLeftX;
-            TopLeftY = 0.0f;
-            Width = float(Desc.Width) - topLeftX;
-            Height = 1.0f;
-            break;
-        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
-            TopLeftX = topLeftX;
-            TopLeftY = 0.0f;
-            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;
-            Height = 1.0f;
-            break;
-        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
-        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
-            TopLeftX = topLeftX;
-            TopLeftY = topLeftY;
-            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;
-            Height = (SubresourceHeight ? float(SubresourceHeight) : 1.0f) - topLeftY;
-            break;
-        default: break;
-        }
-
-        MinDepth = minDepth;
-        MaxDepth = maxDepth;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_BOX : public D3D12_BOX
-{
-    CD3DX12_BOX() = default;
-    explicit CD3DX12_BOX( const D3D12_BOX& o ) noexcept :
-        D3D12_BOX( o )
-    {}
-    explicit CD3DX12_BOX(
-        LONG Left,
-        LONG Right ) noexcept
-    {
-        left = static_cast<UINT>(Left);
-        top = 0;
-        front = 0;
-        right = static_cast<UINT>(Right);
-        bottom = 1;
-        back = 1;
-    }
-    explicit CD3DX12_BOX(
-        LONG Left,
-        LONG Top,
-        LONG Right,
-        LONG Bottom ) noexcept
-    {
-        left = static_cast<UINT>(Left);
-        top = static_cast<UINT>(Top);
-        front = 0;
-        right = static_cast<UINT>(Right);
-        bottom = static_cast<UINT>(Bottom);
-        back = 1;
-    }
-    explicit CD3DX12_BOX(
-        LONG Left,
-        LONG Top,
-        LONG Front,
-        LONG Right,
-        LONG Bottom,
-        LONG Back ) noexcept
-    {
-        left = static_cast<UINT>(Left);
-        top = static_cast<UINT>(Top);
-        front = static_cast<UINT>(Front);
-        right = static_cast<UINT>(Right);
-        bottom = static_cast<UINT>(Bottom);
-        back = static_cast<UINT>(Back);
-    }
-};
-inline bool operator==( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept
-{
-    return l.left == r.left && l.top == r.top && l.front == r.front &&
-        l.right == r.right && l.bottom == r.bottom && l.back == r.back;
-}
-inline bool operator!=( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_DEPTH_STENCIL_DESC : public D3D12_DEPTH_STENCIL_DESC
-{
-    CD3DX12_DEPTH_STENCIL_DESC() = default;
-    explicit CD3DX12_DEPTH_STENCIL_DESC( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept :
-        D3D12_DEPTH_STENCIL_DESC( o )
-    {}
-    explicit CD3DX12_DEPTH_STENCIL_DESC( CD3DX12_DEFAULT ) noexcept
-    {
-        DepthEnable = TRUE;
-        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
-        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
-        StencilEnable = FALSE;
-        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
-        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
-        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
-        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
-        FrontFace = defaultStencilOp;
-        BackFace = defaultStencilOp;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC(
-        BOOL depthEnable,
-        D3D12_DEPTH_WRITE_MASK depthWriteMask,
-        D3D12_COMPARISON_FUNC depthFunc,
-        BOOL stencilEnable,
-        UINT8 stencilReadMask,
-        UINT8 stencilWriteMask,
-        D3D12_STENCIL_OP frontStencilFailOp,
-        D3D12_STENCIL_OP frontStencilDepthFailOp,
-        D3D12_STENCIL_OP frontStencilPassOp,
-        D3D12_COMPARISON_FUNC frontStencilFunc,
-        D3D12_STENCIL_OP backStencilFailOp,
-        D3D12_STENCIL_OP backStencilDepthFailOp,
-        D3D12_STENCIL_OP backStencilPassOp,
-        D3D12_COMPARISON_FUNC backStencilFunc ) noexcept
-    {
-        DepthEnable = depthEnable;
-        DepthWriteMask = depthWriteMask;
-        DepthFunc = depthFunc;
-        StencilEnable = stencilEnable;
-        StencilReadMask = stencilReadMask;
-        StencilWriteMask = stencilWriteMask;
-        FrontFace.StencilFailOp = frontStencilFailOp;
-        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
-        FrontFace.StencilPassOp = frontStencilPassOp;
-        FrontFace.StencilFunc = frontStencilFunc;
-        BackFace.StencilFailOp = backStencilFailOp;
-        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
-        BackFace.StencilPassOp = backStencilPassOp;
-        BackFace.StencilFunc = backStencilFunc;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_DEPTH_STENCIL_DESC1 : public D3D12_DEPTH_STENCIL_DESC1
-{
-    CD3DX12_DEPTH_STENCIL_DESC1() = default;
-    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept :
-        D3D12_DEPTH_STENCIL_DESC1( o )
-    {}
-    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept
-    {
-        DepthEnable                  = o.DepthEnable;
-        DepthWriteMask               = o.DepthWriteMask;
-        DepthFunc                    = o.DepthFunc;
-        StencilEnable                = o.StencilEnable;
-        StencilReadMask              = o.StencilReadMask;
-        StencilWriteMask             = o.StencilWriteMask;
-        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
-        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
-        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
-        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
-        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
-        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
-        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
-        BackFace.StencilFunc         = o.BackFace.StencilFunc;
-        DepthBoundsTestEnable        = FALSE;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC1( CD3DX12_DEFAULT ) noexcept
-    {
-        DepthEnable = TRUE;
-        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
-        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
-        StencilEnable = FALSE;
-        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
-        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
-        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
-        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
-        FrontFace = defaultStencilOp;
-        BackFace = defaultStencilOp;
-        DepthBoundsTestEnable = FALSE;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC1(
-        BOOL depthEnable,
-        D3D12_DEPTH_WRITE_MASK depthWriteMask,
-        D3D12_COMPARISON_FUNC depthFunc,
-        BOOL stencilEnable,
-        UINT8 stencilReadMask,
-        UINT8 stencilWriteMask,
-        D3D12_STENCIL_OP frontStencilFailOp,
-        D3D12_STENCIL_OP frontStencilDepthFailOp,
-        D3D12_STENCIL_OP frontStencilPassOp,
-        D3D12_COMPARISON_FUNC frontStencilFunc,
-        D3D12_STENCIL_OP backStencilFailOp,
-        D3D12_STENCIL_OP backStencilDepthFailOp,
-        D3D12_STENCIL_OP backStencilPassOp,
-        D3D12_COMPARISON_FUNC backStencilFunc,
-        BOOL depthBoundsTestEnable ) noexcept
-    {
-        DepthEnable = depthEnable;
-        DepthWriteMask = depthWriteMask;
-        DepthFunc = depthFunc;
-        StencilEnable = stencilEnable;
-        StencilReadMask = stencilReadMask;
-        StencilWriteMask = stencilWriteMask;
-        FrontFace.StencilFailOp = frontStencilFailOp;
-        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
-        FrontFace.StencilPassOp = frontStencilPassOp;
-        FrontFace.StencilFunc = frontStencilFunc;
-        BackFace.StencilFailOp = backStencilFailOp;
-        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
-        BackFace.StencilPassOp = backStencilPassOp;
-        BackFace.StencilFunc = backStencilFunc;
-        DepthBoundsTestEnable = depthBoundsTestEnable;
-    }
-    operator D3D12_DEPTH_STENCIL_DESC() const noexcept
-    {
-        D3D12_DEPTH_STENCIL_DESC D;
-        D.DepthEnable                  = DepthEnable;
-        D.DepthWriteMask               = DepthWriteMask;
-        D.DepthFunc                    = DepthFunc;
-        D.StencilEnable                = StencilEnable;
-        D.StencilReadMask              = StencilReadMask;
-        D.StencilWriteMask             = StencilWriteMask;
-        D.FrontFace.StencilFailOp      = FrontFace.StencilFailOp;
-        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;
-        D.FrontFace.StencilPassOp      = FrontFace.StencilPassOp;
-        D.FrontFace.StencilFunc        = FrontFace.StencilFunc;
-        D.BackFace.StencilFailOp       = BackFace.StencilFailOp;
-        D.BackFace.StencilDepthFailOp  = BackFace.StencilDepthFailOp;
-        D.BackFace.StencilPassOp       = BackFace.StencilPassOp;
-        D.BackFace.StencilFunc         = BackFace.StencilFunc;
-        return D;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_DEPTH_STENCIL_DESC2 : public D3D12_DEPTH_STENCIL_DESC2
-{
-    CD3DX12_DEPTH_STENCIL_DESC2() = default;
-    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC2& o ) noexcept :
-        D3D12_DEPTH_STENCIL_DESC2( o )
-    {}
-    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept
-    {
-        DepthEnable                  = o.DepthEnable;
-        DepthWriteMask               = o.DepthWriteMask;
-        DepthFunc                    = o.DepthFunc;
-        StencilEnable                = o.StencilEnable;
-        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
-        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
-        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
-        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
-        FrontFace.StencilReadMask    = o.StencilReadMask;
-        FrontFace.StencilWriteMask   = o.StencilWriteMask;
-
-        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
-        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
-        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
-        BackFace.StencilFunc         = o.BackFace.StencilFunc;
-        BackFace.StencilReadMask     = o.StencilReadMask;
-        BackFace.StencilWriteMask    = o.StencilWriteMask;
-        DepthBoundsTestEnable        = o.DepthBoundsTestEnable;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept
-    {
-        DepthEnable                  = o.DepthEnable;
-        DepthWriteMask               = o.DepthWriteMask;
-        DepthFunc                    = o.DepthFunc;
-        StencilEnable                = o.StencilEnable;
-
-        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
-        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
-        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
-        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
-        FrontFace.StencilReadMask    = o.StencilReadMask;
-        FrontFace.StencilWriteMask   = o.StencilWriteMask;
-
-        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
-        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
-        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
-        BackFace.StencilFunc         = o.BackFace.StencilFunc;
-        BackFace.StencilReadMask     = o.StencilReadMask;
-        BackFace.StencilWriteMask    = o.StencilWriteMask;
-
-        DepthBoundsTestEnable        = FALSE;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC2( CD3DX12_DEFAULT ) noexcept
-    {
-        DepthEnable = TRUE;
-        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
-        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
-        StencilEnable = FALSE;
-        const D3D12_DEPTH_STENCILOP_DESC1 defaultStencilOp =
-        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS, D3D12_DEFAULT_STENCIL_READ_MASK, D3D12_DEFAULT_STENCIL_WRITE_MASK };
-        FrontFace = defaultStencilOp;
-        BackFace = defaultStencilOp;
-        DepthBoundsTestEnable = FALSE;
-    }
-    explicit CD3DX12_DEPTH_STENCIL_DESC2(
-        BOOL depthEnable,
-        D3D12_DEPTH_WRITE_MASK depthWriteMask,
-        D3D12_COMPARISON_FUNC depthFunc,
-        BOOL stencilEnable,
-        D3D12_STENCIL_OP frontStencilFailOp,
-        D3D12_STENCIL_OP frontStencilDepthFailOp,
-        D3D12_STENCIL_OP frontStencilPassOp,
-        D3D12_COMPARISON_FUNC frontStencilFunc,
-        UINT8 frontStencilReadMask,
-        UINT8 frontStencilWriteMask,
-        D3D12_STENCIL_OP backStencilFailOp,
-        D3D12_STENCIL_OP backStencilDepthFailOp,
-        D3D12_STENCIL_OP backStencilPassOp,
-        D3D12_COMPARISON_FUNC backStencilFunc,
-        UINT8 backStencilReadMask,
-        UINT8 backStencilWriteMask,
-        BOOL depthBoundsTestEnable ) noexcept
-    {
-        DepthEnable = depthEnable;
-        DepthWriteMask = depthWriteMask;
-        DepthFunc = depthFunc;
-        StencilEnable = stencilEnable;
-
-        FrontFace.StencilFailOp = frontStencilFailOp;
-        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
-        FrontFace.StencilPassOp = frontStencilPassOp;
-        FrontFace.StencilFunc = frontStencilFunc;
-        FrontFace.StencilReadMask = frontStencilReadMask;
-        FrontFace.StencilWriteMask = frontStencilWriteMask;
-
-        BackFace.StencilFailOp = backStencilFailOp;
-        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
-        BackFace.StencilPassOp = backStencilPassOp;
-        BackFace.StencilFunc = backStencilFunc;
-        BackFace.StencilReadMask = backStencilReadMask;
-        BackFace.StencilWriteMask = backStencilWriteMask;
-
-        DepthBoundsTestEnable = depthBoundsTestEnable;
-    }
-
-    operator D3D12_DEPTH_STENCIL_DESC() const noexcept
-    {
-        D3D12_DEPTH_STENCIL_DESC D;
-        D.DepthEnable = DepthEnable;
-        D.DepthWriteMask = DepthWriteMask;
-        D.DepthFunc = DepthFunc;
-        D.StencilEnable = StencilEnable;
-        D.StencilReadMask = FrontFace.StencilReadMask;
-        D.StencilWriteMask = FrontFace.StencilWriteMask;
-        D.FrontFace.StencilFailOp = FrontFace.StencilFailOp;
-        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;
-        D.FrontFace.StencilPassOp = FrontFace.StencilPassOp;
-        D.FrontFace.StencilFunc = FrontFace.StencilFunc;
-        D.BackFace.StencilFailOp = BackFace.StencilFailOp;
-        D.BackFace.StencilDepthFailOp = BackFace.StencilDepthFailOp;
-        D.BackFace.StencilPassOp = BackFace.StencilPassOp;
-        D.BackFace.StencilFunc = BackFace.StencilFunc;
-        return D;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_BLEND_DESC : public D3D12_BLEND_DESC
-{
-    CD3DX12_BLEND_DESC() = default;
-    explicit CD3DX12_BLEND_DESC( const D3D12_BLEND_DESC& o ) noexcept :
-        D3D12_BLEND_DESC( o )
-    {}
-    explicit CD3DX12_BLEND_DESC( CD3DX12_DEFAULT ) noexcept
-    {
-        AlphaToCoverageEnable = FALSE;
-        IndependentBlendEnable = FALSE;
-        const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =
-        {
-            FALSE,FALSE,
-            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
-            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
-            D3D12_LOGIC_OP_NOOP,
-            D3D12_COLOR_WRITE_ENABLE_ALL,
-        };
-        for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
-            RenderTarget[ i ] = defaultRenderTargetBlendDesc;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RASTERIZER_DESC : public D3D12_RASTERIZER_DESC
-{
-    CD3DX12_RASTERIZER_DESC() = default;
-    explicit CD3DX12_RASTERIZER_DESC( const D3D12_RASTERIZER_DESC& o ) noexcept :
-        D3D12_RASTERIZER_DESC( o )
-    {}
-    explicit CD3DX12_RASTERIZER_DESC( CD3DX12_DEFAULT ) noexcept
-    {
-        FillMode = D3D12_FILL_MODE_SOLID;
-        CullMode = D3D12_CULL_MODE_BACK;
-        FrontCounterClockwise = FALSE;
-        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
-        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
-        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
-        DepthClipEnable = TRUE;
-        MultisampleEnable = FALSE;
-        AntialiasedLineEnable = FALSE;
-        ForcedSampleCount = 0;
-        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
-    }
-    explicit CD3DX12_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) noexcept
-    {
-        FillMode = fillMode;
-        CullMode = cullMode;
-        FrontCounterClockwise = frontCounterClockwise;
-        DepthBias = depthBias;
-        DepthBiasClamp = depthBiasClamp;
-        SlopeScaledDepthBias = slopeScaledDepthBias;
-        DepthClipEnable = depthClipEnable;
-        MultisampleEnable = multisampleEnable;
-        AntialiasedLineEnable = antialiasedLineEnable;
-        ForcedSampleCount = forcedSampleCount;
-        ConservativeRaster = conservativeRaster;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RESOURCE_ALLOCATION_INFO : public D3D12_RESOURCE_ALLOCATION_INFO
-{
-    CD3DX12_RESOURCE_ALLOCATION_INFO() = default;
-    explicit CD3DX12_RESOURCE_ALLOCATION_INFO( const D3D12_RESOURCE_ALLOCATION_INFO& o ) noexcept :
-        D3D12_RESOURCE_ALLOCATION_INFO( o )
-    {}
-    CD3DX12_RESOURCE_ALLOCATION_INFO(
-        UINT64 size,
-        UINT64 alignment ) noexcept
-    {
-        SizeInBytes = size;
-        Alignment = alignment;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_HEAP_PROPERTIES : public D3D12_HEAP_PROPERTIES
-{
-    CD3DX12_HEAP_PROPERTIES() = default;
-    explicit CD3DX12_HEAP_PROPERTIES(const D3D12_HEAP_PROPERTIES &o) noexcept :
-        D3D12_HEAP_PROPERTIES(o)
-    {}
-    CD3DX12_HEAP_PROPERTIES(
-        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
-        D3D12_MEMORY_POOL memoryPoolPreference,
-        UINT creationNodeMask = 1,
-        UINT nodeMask = 1 ) noexcept
-    {
-        Type = D3D12_HEAP_TYPE_CUSTOM;
-        CPUPageProperty = cpuPageProperty;
-        MemoryPoolPreference = memoryPoolPreference;
-        CreationNodeMask = creationNodeMask;
-        VisibleNodeMask = nodeMask;
-    }
-    explicit CD3DX12_HEAP_PROPERTIES(
-        D3D12_HEAP_TYPE type,
-        UINT creationNodeMask = 1,
-        UINT nodeMask = 1 ) noexcept
-    {
-        Type = type;
-        CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
-        MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
-        CreationNodeMask = creationNodeMask;
-        VisibleNodeMask = nodeMask;
-    }
-    bool IsCPUAccessible() const noexcept
-    {
-        return Type == D3D12_HEAP_TYPE_UPLOAD || Type == D3D12_HEAP_TYPE_READBACK || (Type == D3D12_HEAP_TYPE_CUSTOM &&
-            (CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK));
-    }
-};
-inline bool operator==( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept
-{
-    return l.Type == r.Type && l.CPUPageProperty == r.CPUPageProperty &&
-        l.MemoryPoolPreference == r.MemoryPoolPreference &&
-        l.CreationNodeMask == r.CreationNodeMask &&
-        l.VisibleNodeMask == r.VisibleNodeMask;
-}
-inline bool operator!=( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_HEAP_DESC : public D3D12_HEAP_DESC
-{
-    CD3DX12_HEAP_DESC() = default;
-    explicit CD3DX12_HEAP_DESC(const D3D12_HEAP_DESC &o) noexcept :
-        D3D12_HEAP_DESC(o)
-    {}
-    CD3DX12_HEAP_DESC(
-        UINT64 size,
-        D3D12_HEAP_PROPERTIES properties,
-        UINT64 alignment = 0,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = size;
-        Properties = properties;
-        Alignment = alignment;
-        Flags = flags;
-    }
-    CD3DX12_HEAP_DESC(
-        UINT64 size,
-        D3D12_HEAP_TYPE type,
-        UINT64 alignment = 0,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = size;
-        Properties = CD3DX12_HEAP_PROPERTIES( type );
-        Alignment = alignment;
-        Flags = flags;
-    }
-    CD3DX12_HEAP_DESC(
-        UINT64 size,
-        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
-        D3D12_MEMORY_POOL memoryPoolPreference,
-        UINT64 alignment = 0,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = size;
-        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );
-        Alignment = alignment;
-        Flags = flags;
-    }
-    CD3DX12_HEAP_DESC(
-        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
-        D3D12_HEAP_PROPERTIES properties,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = resAllocInfo.SizeInBytes;
-        Properties = properties;
-        Alignment = resAllocInfo.Alignment;
-        Flags = flags;
-    }
-    CD3DX12_HEAP_DESC(
-        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
-        D3D12_HEAP_TYPE type,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = resAllocInfo.SizeInBytes;
-        Properties = CD3DX12_HEAP_PROPERTIES( type );
-        Alignment = resAllocInfo.Alignment;
-        Flags = flags;
-    }
-    CD3DX12_HEAP_DESC(
-        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
-        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
-        D3D12_MEMORY_POOL memoryPoolPreference,
-        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
-    {
-        SizeInBytes = resAllocInfo.SizeInBytes;
-        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );
-        Alignment = resAllocInfo.Alignment;
-        Flags = flags;
-    }
-    bool IsCPUAccessible() const noexcept
-    { return static_cast< const CD3DX12_HEAP_PROPERTIES* >( &Properties )->IsCPUAccessible(); }
-};
-inline bool operator==( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept
-{
-    return l.SizeInBytes == r.SizeInBytes &&
-        l.Properties == r.Properties &&
-        l.Alignment == r.Alignment &&
-        l.Flags == r.Flags;
-}
-inline bool operator!=( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_CLEAR_VALUE : public D3D12_CLEAR_VALUE
-{
-    CD3DX12_CLEAR_VALUE() = default;
-    explicit CD3DX12_CLEAR_VALUE(const D3D12_CLEAR_VALUE &o) noexcept :
-        D3D12_CLEAR_VALUE(o)
-    {}
-    CD3DX12_CLEAR_VALUE(
-        DXGI_FORMAT format,
-        const FLOAT color[4] ) noexcept
-    {
-        Format = format;
-        memcpy( Color, color, sizeof( Color ) );
-    }
-    CD3DX12_CLEAR_VALUE(
-        DXGI_FORMAT format,
-        FLOAT depth,
-        UINT8 stencil ) noexcept
-    {
-        Format = format;
-        memset( &Color, 0, sizeof( Color ) );
-        /* Use memcpy to preserve NAN values */
-        memcpy( &DepthStencil.Depth, &depth, sizeof( depth ) );
-        DepthStencil.Stencil = stencil;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RANGE : public D3D12_RANGE
-{
-    CD3DX12_RANGE() = default;
-    explicit CD3DX12_RANGE(const D3D12_RANGE &o) noexcept :
-        D3D12_RANGE(o)
-    {}
-    CD3DX12_RANGE(
-        SIZE_T begin,
-        SIZE_T end ) noexcept
-    {
-        Begin = begin;
-        End = end;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RANGE_UINT64 : public D3D12_RANGE_UINT64
-{
-    CD3DX12_RANGE_UINT64() = default;
-    explicit CD3DX12_RANGE_UINT64(const D3D12_RANGE_UINT64 &o) noexcept :
-        D3D12_RANGE_UINT64(o)
-    {}
-    CD3DX12_RANGE_UINT64(
-        UINT64 begin,
-        UINT64 end ) noexcept
-    {
-        Begin = begin;
-        End = end;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_SUBRESOURCE_RANGE_UINT64 : public D3D12_SUBRESOURCE_RANGE_UINT64
-{
-    CD3DX12_SUBRESOURCE_RANGE_UINT64() = default;
-    explicit CD3DX12_SUBRESOURCE_RANGE_UINT64(const D3D12_SUBRESOURCE_RANGE_UINT64 &o) noexcept :
-        D3D12_SUBRESOURCE_RANGE_UINT64(o)
-    {}
-    CD3DX12_SUBRESOURCE_RANGE_UINT64(
-        UINT subresource,
-        const D3D12_RANGE_UINT64& range ) noexcept
-    {
-        Subresource = subresource;
-        Range = range;
-    }
-    CD3DX12_SUBRESOURCE_RANGE_UINT64(
-        UINT subresource,
-        UINT64 begin,
-        UINT64 end ) noexcept
-    {
-        Subresource = subresource;
-        Range.Begin = begin;
-        Range.End = end;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_SHADER_BYTECODE : public D3D12_SHADER_BYTECODE
-{
-    CD3DX12_SHADER_BYTECODE() = default;
-    explicit CD3DX12_SHADER_BYTECODE(const D3D12_SHADER_BYTECODE &o) noexcept :
-        D3D12_SHADER_BYTECODE(o)
-    {}
-    CD3DX12_SHADER_BYTECODE(
-        _In_ ID3DBlob* pShaderBlob ) noexcept
-    {
-        pShaderBytecode = pShaderBlob->GetBufferPointer();
-        BytecodeLength = pShaderBlob->GetBufferSize();
-    }
-    CD3DX12_SHADER_BYTECODE(
-        const void* _pShaderBytecode,
-        SIZE_T bytecodeLength ) noexcept
-    {
-        pShaderBytecode = _pShaderBytecode;
-        BytecodeLength = bytecodeLength;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_TILED_RESOURCE_COORDINATE : public D3D12_TILED_RESOURCE_COORDINATE
-{
-    CD3DX12_TILED_RESOURCE_COORDINATE() = default;
-    explicit CD3DX12_TILED_RESOURCE_COORDINATE(const D3D12_TILED_RESOURCE_COORDINATE &o) noexcept :
-        D3D12_TILED_RESOURCE_COORDINATE(o)
-    {}
-    CD3DX12_TILED_RESOURCE_COORDINATE(
-        UINT x,
-        UINT y,
-        UINT z,
-        UINT subresource ) noexcept
-    {
-        X = x;
-        Y = y;
-        Z = z;
-        Subresource = subresource;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_TILE_REGION_SIZE : public D3D12_TILE_REGION_SIZE
-{
-    CD3DX12_TILE_REGION_SIZE() = default;
-    explicit CD3DX12_TILE_REGION_SIZE(const D3D12_TILE_REGION_SIZE &o) noexcept :
-        D3D12_TILE_REGION_SIZE(o)
-    {}
-    CD3DX12_TILE_REGION_SIZE(
-        UINT numTiles,
-        BOOL useBox,
-        UINT width,
-        UINT16 height,
-        UINT16 depth ) noexcept
-    {
-        NumTiles = numTiles;
-        UseBox = useBox;
-        Width = width;
-        Height = height;
-        Depth = depth;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_SUBRESOURCE_TILING : public D3D12_SUBRESOURCE_TILING
-{
-    CD3DX12_SUBRESOURCE_TILING() = default;
-    explicit CD3DX12_SUBRESOURCE_TILING(const D3D12_SUBRESOURCE_TILING &o) noexcept :
-        D3D12_SUBRESOURCE_TILING(o)
-    {}
-    CD3DX12_SUBRESOURCE_TILING(
-        UINT widthInTiles,
-        UINT16 heightInTiles,
-        UINT16 depthInTiles,
-        UINT startTileIndexInOverallResource ) noexcept
-    {
-        WidthInTiles = widthInTiles;
-        HeightInTiles = heightInTiles;
-        DepthInTiles = depthInTiles;
-        StartTileIndexInOverallResource = startTileIndexInOverallResource;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_TILE_SHAPE : public D3D12_TILE_SHAPE
-{
-    CD3DX12_TILE_SHAPE() = default;
-    explicit CD3DX12_TILE_SHAPE(const D3D12_TILE_SHAPE &o) noexcept :
-        D3D12_TILE_SHAPE(o)
-    {}
-    CD3DX12_TILE_SHAPE(
-        UINT widthInTexels,
-        UINT heightInTexels,
-        UINT depthInTexels ) noexcept
-    {
-        WidthInTexels = widthInTexels;
-        HeightInTexels = heightInTexels;
-        DepthInTexels = depthInTexels;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RESOURCE_BARRIER : public D3D12_RESOURCE_BARRIER
-{
-    CD3DX12_RESOURCE_BARRIER() = default;
-    explicit CD3DX12_RESOURCE_BARRIER(const D3D12_RESOURCE_BARRIER &o) noexcept :
-        D3D12_RESOURCE_BARRIER(o)
-    {}
-    static inline CD3DX12_RESOURCE_BARRIER Transition(
-        _In_ ID3D12Resource* pResource,
-        D3D12_RESOURCE_STATES stateBefore,
-        D3D12_RESOURCE_STATES stateAfter,
-        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
-        D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE) noexcept
-    {
-        CD3DX12_RESOURCE_BARRIER result = {};
-        D3D12_RESOURCE_BARRIER &barrier = result;
-        result.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
-        result.Flags = flags;
-        barrier.Transition.pResource = pResource;
-        barrier.Transition.StateBefore = stateBefore;
-        barrier.Transition.StateAfter = stateAfter;
-        barrier.Transition.Subresource = subresource;
-        return result;
-    }
-    static inline CD3DX12_RESOURCE_BARRIER Aliasing(
-        _In_ ID3D12Resource* pResourceBefore,
-        _In_ ID3D12Resource* pResourceAfter) noexcept
-    {
-        CD3DX12_RESOURCE_BARRIER result = {};
-        D3D12_RESOURCE_BARRIER &barrier = result;
-        result.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
-        barrier.Aliasing.pResourceBefore = pResourceBefore;
-        barrier.Aliasing.pResourceAfter = pResourceAfter;
-        return result;
-    }
-    static inline CD3DX12_RESOURCE_BARRIER UAV(
-        _In_ ID3D12Resource* pResource) noexcept
-    {
-        CD3DX12_RESOURCE_BARRIER result = {};
-        D3D12_RESOURCE_BARRIER &barrier = result;
-        result.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
-        barrier.UAV.pResource = pResource;
-        return result;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_PACKED_MIP_INFO : public D3D12_PACKED_MIP_INFO
-{
-    CD3DX12_PACKED_MIP_INFO() = default;
-    explicit CD3DX12_PACKED_MIP_INFO(const D3D12_PACKED_MIP_INFO &o) noexcept :
-        D3D12_PACKED_MIP_INFO(o)
-    {}
-    CD3DX12_PACKED_MIP_INFO(
-        UINT8 numStandardMips,
-        UINT8 numPackedMips,
-        UINT numTilesForPackedMips,
-        UINT startTileIndexInOverallResource ) noexcept
-    {
-        NumStandardMips = numStandardMips;
-        NumPackedMips = numPackedMips;
-        NumTilesForPackedMips = numTilesForPackedMips;
-        StartTileIndexInOverallResource = startTileIndexInOverallResource;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_SUBRESOURCE_FOOTPRINT : public D3D12_SUBRESOURCE_FOOTPRINT
-{
-    CD3DX12_SUBRESOURCE_FOOTPRINT() = default;
-    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(const D3D12_SUBRESOURCE_FOOTPRINT &o) noexcept :
-        D3D12_SUBRESOURCE_FOOTPRINT(o)
-    {}
-    CD3DX12_SUBRESOURCE_FOOTPRINT(
-        DXGI_FORMAT format,
-        UINT width,
-        UINT height,
-        UINT depth,
-        UINT rowPitch ) noexcept
-    {
-        Format = format;
-        Width = width;
-        Height = height;
-        Depth = depth;
-        RowPitch = rowPitch;
-    }
-    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(
-        const D3D12_RESOURCE_DESC& resDesc,
-        UINT rowPitch ) noexcept
-    {
-        Format = resDesc.Format;
-        Width = UINT( resDesc.Width );
-        Height = resDesc.Height;
-        Depth = (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? resDesc.DepthOrArraySize : 1u);
-        RowPitch = rowPitch;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_TEXTURE_COPY_LOCATION : public D3D12_TEXTURE_COPY_LOCATION
-{
-    CD3DX12_TEXTURE_COPY_LOCATION() = default;
-    explicit CD3DX12_TEXTURE_COPY_LOCATION(const D3D12_TEXTURE_COPY_LOCATION &o) noexcept :
-        D3D12_TEXTURE_COPY_LOCATION(o)
-    {}
-    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes) noexcept
-    {
-        pResource = pRes;
-        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
-        PlacedFootprint = {};
-    }
-    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, D3D12_PLACED_SUBRESOURCE_FOOTPRINT const& Footprint) noexcept
-    {
-        pResource = pRes;
-        Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
-        PlacedFootprint = Footprint;
-    }
-    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, UINT Sub) noexcept
-    {
-        pResource = pRes;
-        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
-        PlacedFootprint = {};
-        SubresourceIndex = Sub;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_DESCRIPTOR_RANGE : public D3D12_DESCRIPTOR_RANGE
-{
-    CD3DX12_DESCRIPTOR_RANGE() = default;
-    explicit CD3DX12_DESCRIPTOR_RANGE(const D3D12_DESCRIPTOR_RANGE &o) noexcept :
-        D3D12_DESCRIPTOR_RANGE(o)
-    {}
-    CD3DX12_DESCRIPTOR_RANGE(
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);
-    }
-
-    inline void Init(
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_DESCRIPTOR_RANGE &range,
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        range.RangeType = rangeType;
-        range.NumDescriptors = numDescriptors;
-        range.BaseShaderRegister = baseShaderRegister;
-        range.RegisterSpace = registerSpace;
-        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_DESCRIPTOR_TABLE : public D3D12_ROOT_DESCRIPTOR_TABLE
-{
-    CD3DX12_ROOT_DESCRIPTOR_TABLE() = default;
-    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE(const D3D12_ROOT_DESCRIPTOR_TABLE &o) noexcept :
-        D3D12_ROOT_DESCRIPTOR_TABLE(o)
-    {}
-    CD3DX12_ROOT_DESCRIPTOR_TABLE(
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
-    {
-        Init(numDescriptorRanges, _pDescriptorRanges);
-    }
-
-    inline void Init(
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
-    {
-        Init(*this, numDescriptorRanges, _pDescriptorRanges);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE &rootDescriptorTable,
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
-    {
-        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;
-        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_CONSTANTS : public D3D12_ROOT_CONSTANTS
-{
-    CD3DX12_ROOT_CONSTANTS() = default;
-    explicit CD3DX12_ROOT_CONSTANTS(const D3D12_ROOT_CONSTANTS &o) noexcept :
-        D3D12_ROOT_CONSTANTS(o)
-    {}
-    CD3DX12_ROOT_CONSTANTS(
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0) noexcept
-    {
-        Init(num32BitValues, shaderRegister, registerSpace);
-    }
-
-    inline void Init(
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0) noexcept
-    {
-        Init(*this, num32BitValues, shaderRegister, registerSpace);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_ROOT_CONSTANTS &rootConstants,
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0) noexcept
-    {
-        rootConstants.Num32BitValues = num32BitValues;
-        rootConstants.ShaderRegister = shaderRegister;
-        rootConstants.RegisterSpace = registerSpace;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_DESCRIPTOR : public D3D12_ROOT_DESCRIPTOR
-{
-    CD3DX12_ROOT_DESCRIPTOR() = default;
-    explicit CD3DX12_ROOT_DESCRIPTOR(const D3D12_ROOT_DESCRIPTOR &o) noexcept :
-        D3D12_ROOT_DESCRIPTOR(o)
-    {}
-    CD3DX12_ROOT_DESCRIPTOR(
-        UINT shaderRegister,
-        UINT registerSpace = 0) noexcept
-    {
-        Init(shaderRegister, registerSpace);
-    }
-
-    inline void Init(
-        UINT shaderRegister,
-        UINT registerSpace = 0) noexcept
-    {
-        Init(*this, shaderRegister, registerSpace);
-    }
-
-    static inline void Init(_Out_ D3D12_ROOT_DESCRIPTOR &table, UINT shaderRegister, UINT registerSpace = 0) noexcept
-    {
-        table.ShaderRegister = shaderRegister;
-        table.RegisterSpace = registerSpace;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_PARAMETER : public D3D12_ROOT_PARAMETER
-{
-    CD3DX12_ROOT_PARAMETER() = default;
-    explicit CD3DX12_ROOT_PARAMETER(const D3D12_ROOT_PARAMETER &o) noexcept :
-        D3D12_ROOT_PARAMETER(o)
-    {}
-
-    static inline void InitAsDescriptorTable(
-        _Out_ D3D12_ROOT_PARAMETER &rootParam,
-        UINT numDescriptorRanges,
-        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR_TABLE::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);
-    }
-
-    static inline void InitAsConstants(
-        _Out_ D3D12_ROOT_PARAMETER &rootParam,
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);
-    }
-
-    static inline void InitAsConstantBufferView(
-        _Out_ D3D12_ROOT_PARAMETER &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
-    }
-
-    static inline void InitAsShaderResourceView(
-        _Out_ D3D12_ROOT_PARAMETER &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
-    }
-
-    static inline void InitAsUnorderedAccessView(
-        _Out_ D3D12_ROOT_PARAMETER &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
-    }
-
-    inline void InitAsDescriptorTable(
-        UINT numDescriptorRanges,
-        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);
-    }
-
-    inline void InitAsConstants(
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);
-    }
-
-    inline void InitAsConstantBufferView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsConstantBufferView(*this, shaderRegister, registerSpace, visibility);
-    }
-
-    inline void InitAsShaderResourceView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsShaderResourceView(*this, shaderRegister, registerSpace, visibility);
-    }
-
-    inline void InitAsUnorderedAccessView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, visibility);
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_STATIC_SAMPLER_DESC : public D3D12_STATIC_SAMPLER_DESC
-{
-    CD3DX12_STATIC_SAMPLER_DESC() = default;
-    explicit CD3DX12_STATIC_SAMPLER_DESC(const D3D12_STATIC_SAMPLER_DESC &o) noexcept :
-        D3D12_STATIC_SAMPLER_DESC(o)
-    {}
-    CD3DX12_STATIC_SAMPLER_DESC(
-         UINT shaderRegister,
-         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
-         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         FLOAT mipLODBias = 0,
-         UINT maxAnisotropy = 16,
-         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
-         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
-         FLOAT minLOD = 0.f,
-         FLOAT maxLOD = D3D12_FLOAT32_MAX,
-         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
-         UINT registerSpace = 0) noexcept
-    {
-        Init(
-            shaderRegister,
-            filter,
-            addressU,
-            addressV,
-            addressW,
-            mipLODBias,
-            maxAnisotropy,
-            comparisonFunc,
-            borderColor,
-            minLOD,
-            maxLOD,
-            shaderVisibility,
-            registerSpace);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_STATIC_SAMPLER_DESC &samplerDesc,
-         UINT shaderRegister,
-         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
-         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         FLOAT mipLODBias = 0,
-         UINT maxAnisotropy = 16,
-         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
-         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
-         FLOAT minLOD = 0.f,
-         FLOAT maxLOD = D3D12_FLOAT32_MAX,
-         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
-         UINT registerSpace = 0) noexcept
-    {
-        samplerDesc.ShaderRegister = shaderRegister;
-        samplerDesc.Filter = filter;
-        samplerDesc.AddressU = addressU;
-        samplerDesc.AddressV = addressV;
-        samplerDesc.AddressW = addressW;
-        samplerDesc.MipLODBias = mipLODBias;
-        samplerDesc.MaxAnisotropy = maxAnisotropy;
-        samplerDesc.ComparisonFunc = comparisonFunc;
-        samplerDesc.BorderColor = borderColor;
-        samplerDesc.MinLOD = minLOD;
-        samplerDesc.MaxLOD = maxLOD;
-        samplerDesc.ShaderVisibility = shaderVisibility;
-        samplerDesc.RegisterSpace = registerSpace;
-    }
-    inline void Init(
-         UINT shaderRegister,
-         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
-         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
-         FLOAT mipLODBias = 0,
-         UINT maxAnisotropy = 16,
-         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
-         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
-         FLOAT minLOD = 0.f,
-         FLOAT maxLOD = D3D12_FLOAT32_MAX,
-         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
-         UINT registerSpace = 0) noexcept
-    {
-        Init(
-            *this,
-            shaderRegister,
-            filter,
-            addressU,
-            addressV,
-            addressW,
-            mipLODBias,
-            maxAnisotropy,
-            comparisonFunc,
-            borderColor,
-            minLOD,
-            maxLOD,
-            shaderVisibility,
-            registerSpace);
-    }
-
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_SIGNATURE_DESC : public D3D12_ROOT_SIGNATURE_DESC
-{
-    CD3DX12_ROOT_SIGNATURE_DESC() = default;
-    explicit CD3DX12_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept :
-        D3D12_ROOT_SIGNATURE_DESC(o)
-    {}
-    CD3DX12_ROOT_SIGNATURE_DESC(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-    CD3DX12_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept
-    {
-        Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
-    }
-
-    inline void Init(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_ROOT_SIGNATURE_DESC &desc,
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        desc.NumParameters = numParameters;
-        desc.pParameters = _pParameters;
-        desc.NumStaticSamplers = numStaticSamplers;
-        desc.pStaticSamplers = _pStaticSamplers;
-        desc.Flags = flags;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_DESCRIPTOR_RANGE1 : public D3D12_DESCRIPTOR_RANGE1
-{
-    CD3DX12_DESCRIPTOR_RANGE1() = default;
-    explicit CD3DX12_DESCRIPTOR_RANGE1(const D3D12_DESCRIPTOR_RANGE1 &o) noexcept :
-        D3D12_DESCRIPTOR_RANGE1(o)
-    {}
-    CD3DX12_DESCRIPTOR_RANGE1(
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);
-    }
-
-    inline void Init(
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_DESCRIPTOR_RANGE1 &range,
-        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
-        UINT numDescriptors,
-        UINT baseShaderRegister,
-        UINT registerSpace = 0,
-        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
-        UINT offsetInDescriptorsFromTableStart =
-        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
-    {
-        range.RangeType = rangeType;
-        range.NumDescriptors = numDescriptors;
-        range.BaseShaderRegister = baseShaderRegister;
-        range.RegisterSpace = registerSpace;
-        range.Flags = flags;
-        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_DESCRIPTOR_TABLE1 : public D3D12_ROOT_DESCRIPTOR_TABLE1
-{
-    CD3DX12_ROOT_DESCRIPTOR_TABLE1() = default;
-    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE1(const D3D12_ROOT_DESCRIPTOR_TABLE1 &o) noexcept :
-        D3D12_ROOT_DESCRIPTOR_TABLE1(o)
-    {}
-    CD3DX12_ROOT_DESCRIPTOR_TABLE1(
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
-    {
-        Init(numDescriptorRanges, _pDescriptorRanges);
-    }
-
-    inline void Init(
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
-    {
-        Init(*this, numDescriptorRanges, _pDescriptorRanges);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE1 &rootDescriptorTable,
-        UINT numDescriptorRanges,
-        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
-    {
-        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;
-        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_DESCRIPTOR1 : public D3D12_ROOT_DESCRIPTOR1
-{
-    CD3DX12_ROOT_DESCRIPTOR1() = default;
-    explicit CD3DX12_ROOT_DESCRIPTOR1(const D3D12_ROOT_DESCRIPTOR1 &o) noexcept :
-        D3D12_ROOT_DESCRIPTOR1(o)
-    {}
-    CD3DX12_ROOT_DESCRIPTOR1(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
-    {
-        Init(shaderRegister, registerSpace, flags);
-    }
-
-    inline void Init(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
-    {
-        Init(*this, shaderRegister, registerSpace, flags);
-    }
-
-    static inline void Init(
-        _Out_ D3D12_ROOT_DESCRIPTOR1 &table,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
-    {
-        table.ShaderRegister = shaderRegister;
-        table.RegisterSpace = registerSpace;
-        table.Flags = flags;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_ROOT_PARAMETER1 : public D3D12_ROOT_PARAMETER1
-{
-    CD3DX12_ROOT_PARAMETER1() = default;
-    explicit CD3DX12_ROOT_PARAMETER1(const D3D12_ROOT_PARAMETER1 &o) noexcept :
-        D3D12_ROOT_PARAMETER1(o)
-    {}
-
-    static inline void InitAsDescriptorTable(
-        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
-        UINT numDescriptorRanges,
-        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR_TABLE1::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);
-    }
-
-    static inline void InitAsConstants(
-        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);
-    }
-
-    static inline void InitAsConstantBufferView(
-        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
-    }
-
-    static inline void InitAsShaderResourceView(
-        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
-    }
-
-    static inline void InitAsUnorderedAccessView(
-        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
-        rootParam.ShaderVisibility = visibility;
-        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
-    }
-
-    inline void InitAsDescriptorTable(
-        UINT numDescriptorRanges,
-        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);
-    }
-
-    inline void InitAsConstants(
-        UINT num32BitValues,
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);
-    }
-
-    inline void InitAsConstantBufferView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsConstantBufferView(*this, shaderRegister, registerSpace, flags, visibility);
-    }
-
-    inline void InitAsShaderResourceView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsShaderResourceView(*this, shaderRegister, registerSpace, flags, visibility);
-    }
-
-    inline void InitAsUnorderedAccessView(
-        UINT shaderRegister,
-        UINT registerSpace = 0,
-        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
-        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
-    {
-        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, flags, visibility);
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC : public D3D12_VERSIONED_ROOT_SIGNATURE_DESC
-{
-    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC() = default;
-    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC &o) noexcept :
-        D3D12_VERSIONED_ROOT_SIGNATURE_DESC(o)
-    {}
-    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept
-    {
-        Version = D3D_ROOT_SIGNATURE_VERSION_1_0;
-        Desc_1_0 = o;
-    }
-    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC1 &o) noexcept
-    {
-        Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
-        Desc_1_1 = o;
-    }
-    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init_1_0(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init_1_1(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept
-    {
-        Init_1_1(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
-    }
-
-    inline void Init_1_0(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init_1_0(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-
-    static inline void Init_1_0(
-        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0;
-        desc.Desc_1_0.NumParameters = numParameters;
-        desc.Desc_1_0.pParameters = _pParameters;
-        desc.Desc_1_0.NumStaticSamplers = numStaticSamplers;
-        desc.Desc_1_0.pStaticSamplers = _pStaticSamplers;
-        desc.Desc_1_0.Flags = flags;
-    }
-
-    inline void Init_1_1(
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        Init_1_1(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
-    }
-
-    static inline void Init_1_1(
-        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,
-        UINT numParameters,
-        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
-        UINT numStaticSamplers = 0,
-        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
-        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
-    {
-        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
-        desc.Desc_1_1.NumParameters = numParameters;
-        desc.Desc_1_1.pParameters = _pParameters;
-        desc.Desc_1_1.NumStaticSamplers = numStaticSamplers;
-        desc.Desc_1_1.pStaticSamplers = _pStaticSamplers;
-        desc.Desc_1_1.Flags = flags;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_CPU_DESCRIPTOR_HANDLE : public D3D12_CPU_DESCRIPTOR_HANDLE
-{
-    CD3DX12_CPU_DESCRIPTOR_HANDLE() = default;
-    explicit CD3DX12_CPU_DESCRIPTOR_HANDLE(const D3D12_CPU_DESCRIPTOR_HANDLE &o) noexcept :
-        D3D12_CPU_DESCRIPTOR_HANDLE(o)
-    {}
-    CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }
-    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept
-    {
-        InitOffsetted(other, offsetScaledByIncrementSize);
-    }
-    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);
-    }
-    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        ptr = SIZE_T(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
-        return *this;
-    }
-    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept
-    {
-        ptr = SIZE_T(INT64(ptr) + INT64(offsetScaledByIncrementSize));
-        return *this;
-    }
-    bool operator==(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept
-    {
-        return (ptr == other.ptr);
-    }
-    bool operator!=(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept
-    {
-        return (ptr != other.ptr);
-    }
-    CD3DX12_CPU_DESCRIPTOR_HANDLE &operator=(const D3D12_CPU_DESCRIPTOR_HANDLE &other) noexcept
-    {
-        ptr = other.ptr;
-        return *this;
-    }
-
-    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
-    {
-        InitOffsetted(*this, base, offsetScaledByIncrementSize);
-    }
-
-    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);
-    }
-
-    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
-    {
-        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));
-    }
-
-    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE
-{
-    CD3DX12_GPU_DESCRIPTOR_HANDLE() = default;
-    explicit CD3DX12_GPU_DESCRIPTOR_HANDLE(const D3D12_GPU_DESCRIPTOR_HANDLE &o) noexcept :
-        D3D12_GPU_DESCRIPTOR_HANDLE(o)
-    {}
-    CD3DX12_GPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }
-    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept
-    {
-        InitOffsetted(other, offsetScaledByIncrementSize);
-    }
-    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);
-    }
-    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        ptr = UINT64(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
-        return *this;
-    }
-    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept
-    {
-        ptr = UINT64(INT64(ptr) + INT64(offsetScaledByIncrementSize));
-        return *this;
-    }
-    inline bool operator==(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept
-    {
-        return (ptr == other.ptr);
-    }
-    inline bool operator!=(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept
-    {
-        return (ptr != other.ptr);
-    }
-    CD3DX12_GPU_DESCRIPTOR_HANDLE &operator=(const D3D12_GPU_DESCRIPTOR_HANDLE &other) noexcept
-    {
-        ptr = other.ptr;
-        return *this;
-    }
-
-    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
-    {
-        InitOffsetted(*this, base, offsetScaledByIncrementSize);
-    }
-
-    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);
-    }
-
-    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
-    {
-        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));
-    }
-
-    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
-    {
-        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-constexpr UINT D3D12CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize ) noexcept
-{
-    return MipSlice + ArraySlice * MipLevels + PlaneSlice * MipLevels * ArraySize;
-}
-
-//------------------------------------------------------------------------------------------------
-template <typename T, typename U, typename V>
-inline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept
-{
-    MipSlice = static_cast<T>(Subresource % MipLevels);
-    ArraySlice = static_cast<U>((Subresource / MipLevels) % ArraySize);
-    PlaneSlice = static_cast<V>(Subresource / (MipLevels * ArraySize));
-}
-
-//------------------------------------------------------------------------------------------------
-inline UINT8 D3D12GetFormatPlaneCount(
-    _In_ ID3D12Device* pDevice,
-    DXGI_FORMAT Format
-    ) noexcept
-{
-    D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { Format, 0 };
-    if (FAILED(pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))
-    {
-        return 0;
-    }
-    return formatInfo.PlaneCount;
-}
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RESOURCE_DESC : public D3D12_RESOURCE_DESC
-{
-    CD3DX12_RESOURCE_DESC() = default;
-    explicit CD3DX12_RESOURCE_DESC( const D3D12_RESOURCE_DESC& o ) noexcept :
-        D3D12_RESOURCE_DESC( o )
-    {}
-    CD3DX12_RESOURCE_DESC(
-        D3D12_RESOURCE_DIMENSION dimension,
-        UINT64 alignment,
-        UINT64 width,
-        UINT height,
-        UINT16 depthOrArraySize,
-        UINT16 mipLevels,
-        DXGI_FORMAT format,
-        UINT sampleCount,
-        UINT sampleQuality,
-        D3D12_TEXTURE_LAYOUT layout,
-        D3D12_RESOURCE_FLAGS flags ) noexcept
-    {
-        Dimension = dimension;
-        Alignment = alignment;
-        Width = width;
-        Height = height;
-        DepthOrArraySize = depthOrArraySize;
-        MipLevels = mipLevels;
-        Format = format;
-        SampleDesc.Count = sampleCount;
-        SampleDesc.Quality = sampleQuality;
-        Layout = layout;
-        Flags = flags;
-    }
-    static inline CD3DX12_RESOURCE_DESC Buffer(
-        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,
-            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );
-    }
-    static inline CD3DX12_RESOURCE_DESC Buffer(
-        UINT64 width,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,
-            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );
-    }
-    static inline CD3DX12_RESOURCE_DESC Tex1D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT16 arraySize = 1,
-        UINT16 mipLevels = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,
-            mipLevels, format, 1, 0, layout, flags );
-    }
-    static inline CD3DX12_RESOURCE_DESC Tex2D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT height,
-        UINT16 arraySize = 1,
-        UINT16 mipLevels = 0,
-        UINT sampleCount = 1,
-        UINT sampleQuality = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,
-            mipLevels, format, sampleCount, sampleQuality, layout, flags );
-    }
-    static inline CD3DX12_RESOURCE_DESC Tex3D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT height,
-        UINT16 depth,
-        UINT16 mipLevels = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,
-            mipLevels, format, 1, 0, layout, flags );
-    }
-    inline UINT16 Depth() const noexcept
-    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
-    inline UINT16 ArraySize() const noexcept
-    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
-    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept
-    { return D3D12GetFormatPlaneCount(pDevice, Format); }
-    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept
-    { return static_cast<UINT>(MipLevels) * ArraySize() * PlaneCount(pDevice); }
-    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept
-    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }
-};
-inline bool operator==( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept
-{
-    return l.Dimension == r.Dimension &&
-        l.Alignment == r.Alignment &&
-        l.Width == r.Width &&
-        l.Height == r.Height &&
-        l.DepthOrArraySize == r.DepthOrArraySize &&
-        l.MipLevels == r.MipLevels &&
-        l.Format == r.Format &&
-        l.SampleDesc.Count == r.SampleDesc.Count &&
-        l.SampleDesc.Quality == r.SampleDesc.Quality &&
-        l.Layout == r.Layout &&
-        l.Flags == r.Flags;
-}
-inline bool operator!=( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RESOURCE_DESC1 : public D3D12_RESOURCE_DESC1
-{
-    CD3DX12_RESOURCE_DESC1() = default;
-    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC1& o ) noexcept :
-        D3D12_RESOURCE_DESC1( o )
-    {}
-    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC& o ) noexcept
-    {
-        Dimension = o.Dimension;
-        Alignment = o.Alignment;
-        Width = o.Width;
-        Height = o.Height;
-        DepthOrArraySize = o.DepthOrArraySize;
-        MipLevels = o.MipLevels;
-        Format = o.Format;
-        SampleDesc = o.SampleDesc;
-        Layout = o.Layout;
-        Flags = o.Flags;
-        SamplerFeedbackMipRegion = {};
-    }
-    CD3DX12_RESOURCE_DESC1(
-        D3D12_RESOURCE_DIMENSION dimension,
-        UINT64 alignment,
-        UINT64 width,
-        UINT height,
-        UINT16 depthOrArraySize,
-        UINT16 mipLevels,
-        DXGI_FORMAT format,
-        UINT sampleCount,
-        UINT sampleQuality,
-        D3D12_TEXTURE_LAYOUT layout,
-        D3D12_RESOURCE_FLAGS flags,
-        UINT samplerFeedbackMipRegionWidth = 0,
-        UINT samplerFeedbackMipRegionHeight = 0,
-        UINT samplerFeedbackMipRegionDepth = 0) noexcept
-    {
-        Dimension = dimension;
-        Alignment = alignment;
-        Width = width;
-        Height = height;
-        DepthOrArraySize = depthOrArraySize;
-        MipLevels = mipLevels;
-        Format = format;
-        SampleDesc.Count = sampleCount;
-        SampleDesc.Quality = sampleQuality;
-        Layout = layout;
-        Flags = flags;
-        SamplerFeedbackMipRegion.Width = samplerFeedbackMipRegionWidth;
-        SamplerFeedbackMipRegion.Height = samplerFeedbackMipRegionHeight;
-        SamplerFeedbackMipRegion.Depth = samplerFeedbackMipRegionDepth;
-    }
-    static inline CD3DX12_RESOURCE_DESC1 Buffer(
-        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,
-            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );
-    }
-    static inline CD3DX12_RESOURCE_DESC1 Buffer(
-        UINT64 width,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,
-            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );
-    }
-    static inline CD3DX12_RESOURCE_DESC1 Tex1D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT16 arraySize = 1,
-        UINT16 mipLevels = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,
-            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );
-    }
-    static inline CD3DX12_RESOURCE_DESC1 Tex2D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT height,
-        UINT16 arraySize = 1,
-        UINT16 mipLevels = 0,
-        UINT sampleCount = 1,
-        UINT sampleQuality = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0,
-        UINT samplerFeedbackMipRegionWidth = 0,
-        UINT samplerFeedbackMipRegionHeight = 0,
-        UINT samplerFeedbackMipRegionDepth = 0) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,
-            mipLevels, format, sampleCount, sampleQuality, layout, flags, samplerFeedbackMipRegionWidth,
-            samplerFeedbackMipRegionHeight, samplerFeedbackMipRegionDepth );
-    }
-    static inline CD3DX12_RESOURCE_DESC1 Tex3D(
-        DXGI_FORMAT format,
-        UINT64 width,
-        UINT height,
-        UINT16 depth,
-        UINT16 mipLevels = 0,
-        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
-        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        UINT64 alignment = 0 ) noexcept
-    {
-        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,
-            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );
-    }
-    inline UINT16 Depth() const noexcept
-    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
-    inline UINT16 ArraySize() const noexcept
-    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
-    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept
-    { return D3D12GetFormatPlaneCount(pDevice, Format); }
-    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept
-    { return static_cast<UINT>(MipLevels) * ArraySize() * PlaneCount(pDevice); }
-    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept
-    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }
-};
-inline bool operator==( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept
-{
-    return l.Dimension == r.Dimension &&
-        l.Alignment == r.Alignment &&
-        l.Width == r.Width &&
-        l.Height == r.Height &&
-        l.DepthOrArraySize == r.DepthOrArraySize &&
-        l.MipLevels == r.MipLevels &&
-        l.Format == r.Format &&
-        l.SampleDesc.Count == r.SampleDesc.Count &&
-        l.SampleDesc.Quality == r.SampleDesc.Quality &&
-        l.Layout == r.Layout &&
-        l.Flags == r.Flags &&
-        l.SamplerFeedbackMipRegion.Width == r.SamplerFeedbackMipRegion.Width &&
-        l.SamplerFeedbackMipRegion.Height == r.SamplerFeedbackMipRegion.Height &&
-        l.SamplerFeedbackMipRegion.Depth == r.SamplerFeedbackMipRegion.Depth;
-}
-inline bool operator!=( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept
-{ return !( l == r ); }
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_VIEW_INSTANCING_DESC : public D3D12_VIEW_INSTANCING_DESC
-{
-    CD3DX12_VIEW_INSTANCING_DESC() = default;
-    explicit CD3DX12_VIEW_INSTANCING_DESC( const D3D12_VIEW_INSTANCING_DESC& o ) noexcept :
-        D3D12_VIEW_INSTANCING_DESC( o )
-    {}
-    explicit CD3DX12_VIEW_INSTANCING_DESC( CD3DX12_DEFAULT ) noexcept
-    {
-        ViewInstanceCount = 0;
-        pViewInstanceLocations = nullptr;
-        Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
-    }
-    explicit CD3DX12_VIEW_INSTANCING_DESC(
-        UINT InViewInstanceCount,
-        const D3D12_VIEW_INSTANCE_LOCATION* InViewInstanceLocations,
-        D3D12_VIEW_INSTANCING_FLAGS InFlags) noexcept
-    {
-        ViewInstanceCount = InViewInstanceCount;
-        pViewInstanceLocations = InViewInstanceLocations;
-        Flags = InFlags;
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-// Row-by-row memcpy
-inline void MemcpySubresource(
-    _In_ const D3D12_MEMCPY_DEST* pDest,
-    _In_ const D3D12_SUBRESOURCE_DATA* pSrc,
-    SIZE_T RowSizeInBytes,
-    UINT NumRows,
-    UINT NumSlices) noexcept
-{
-    for (UINT z = 0; z < NumSlices; ++z)
-    {
-        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
-        auto pSrcSlice = static_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * LONG_PTR(z);
-        for (UINT y = 0; y < NumRows; ++y)
-        {
-            memcpy(pDestSlice + pDest->RowPitch * y,
-                   pSrcSlice + pSrc->RowPitch * LONG_PTR(y),
-                   RowSizeInBytes);
-        }
-    }
-}
-
-//------------------------------------------------------------------------------------------------
-// Row-by-row memcpy
-inline void MemcpySubresource(
-    _In_ const D3D12_MEMCPY_DEST* pDest,
-    _In_ const void* pResourceData,
-    _In_ const D3D12_SUBRESOURCE_INFO* pSrc,
-    SIZE_T RowSizeInBytes,
-    UINT NumRows,
-    UINT NumSlices) noexcept
-{
-    for (UINT z = 0; z < NumSlices; ++z)
-    {
-        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
-        auto pSrcSlice = (static_cast<const BYTE*>(pResourceData) + pSrc->Offset) + pSrc->DepthPitch * ULONG_PTR(z);
-        for (UINT y = 0; y < NumRows; ++y)
-        {
-            memcpy(pDestSlice + pDest->RowPitch * y,
-                pSrcSlice + pSrc->RowPitch * ULONG_PTR(y),
-                RowSizeInBytes);
-        }
-    }
-}
-
-//------------------------------------------------------------------------------------------------
-// Returns required size of a buffer to be used for data upload
-inline UINT64 GetRequiredIntermediateSize(
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources) noexcept
-{
-    const auto Desc = pDestinationResource->GetDesc();
-    UINT64 RequiredSize = 0;
-
-    ID3D12Device* pDevice = nullptr;
-    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
-    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);
-    pDevice->Release();
-
-    return RequiredSize;
-}
-
-//------------------------------------------------------------------------------------------------
-// All arrays must be populated (e.g. by calling GetCopyableFootprints)
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
-    UINT64 RequiredSize,
-    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
-    _In_reads_(NumSubresources) const UINT* pNumRows,
-    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
-{
-    // Minor validation
-    const auto IntermediateDesc = pIntermediate->GetDesc();
-    const auto DestinationDesc = pDestinationResource->GetDesc();
-    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
-        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
-        RequiredSize > SIZE_T(-1) ||
-        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
-            (FirstSubresource != 0 || NumSubresources != 1)))
-    {
-        return 0;
-    }
-
-    BYTE* pData;
-    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
-    if (FAILED(hr))
-    {
-        return 0;
-    }
-
-    for (UINT i = 0; i < NumSubresources; ++i)
-    {
-        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
-        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
-        MemcpySubresource(&DestData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
-    }
-    pIntermediate->Unmap(0, nullptr);
-
-    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
-    {
-        pCmdList->CopyBufferRegion(
-            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
-    }
-    else
-    {
-        for (UINT i = 0; i < NumSubresources; ++i)
-        {
-            const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
-            const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
-            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
-        }
-    }
-    return RequiredSize;
-}
-
-//------------------------------------------------------------------------------------------------
-// All arrays must be populated (e.g. by calling GetCopyableFootprints)
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
-    UINT64 RequiredSize,
-    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
-    _In_reads_(NumSubresources) const UINT* pNumRows,
-    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
-    _In_ const void* pResourceData,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
-{
-    // Minor validation
-    const auto IntermediateDesc = pIntermediate->GetDesc();
-    const auto DestinationDesc = pDestinationResource->GetDesc();
-    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
-        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
-        RequiredSize > SIZE_T(-1) ||
-        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
-            (FirstSubresource != 0 || NumSubresources != 1)))
-    {
-        return 0;
-    }
-
-    BYTE* pData;
-    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
-    if (FAILED(hr))
-    {
-        return 0;
-    }
-
-    for (UINT i = 0; i < NumSubresources; ++i)
-    {
-        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
-        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
-        MemcpySubresource(&DestData, pResourceData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
-    }
-    pIntermediate->Unmap(0, nullptr);
-
-    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
-    {
-        pCmdList->CopyBufferRegion(
-            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
-    }
-    else
-    {
-        for (UINT i = 0; i < NumSubresources; ++i)
-        {
-            const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
-            const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
-            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
-        }
-    }
-    return RequiredSize;
-}
-
-//------------------------------------------------------------------------------------------------
-// Heap-allocating UpdateSubresources implementation
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    UINT64 IntermediateOffset,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
-{
-    UINT64 RequiredSize = 0;
-    const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
-    if (MemToAlloc > SIZE_MAX)
-    {
-       return 0;
-    }
-    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
-    if (pMem == nullptr)
-    {
-       return 0;
-    }
-    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
-    auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
-    auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
-
-    const auto Desc = pDestinationResource->GetDesc();
-    ID3D12Device* pDevice = nullptr;
-    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
-    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
-    pDevice->Release();
-
-    const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);
-    HeapFree(GetProcessHeap(), 0, pMem);
-    return Result;
-}
-
-//------------------------------------------------------------------------------------------------
-// Heap-allocating UpdateSubresources implementation
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    UINT64 IntermediateOffset,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
-    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
-    _In_ const void* pResourceData,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
-{
-    UINT64 RequiredSize = 0;
-    const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
-    if (MemToAlloc > SIZE_MAX)
-    {
-        return 0;
-    }
-    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
-    if (pMem == nullptr)
-    {
-        return 0;
-    }
-    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
-    auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
-    auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
-
-    const auto Desc = pDestinationResource->GetDesc();
-    ID3D12Device* pDevice = nullptr;
-    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
-    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
-    pDevice->Release();
-
-    const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pResourceData, pSrcData);
-    HeapFree(GetProcessHeap(), 0, pMem);
-    return Result;
-}
-
-//------------------------------------------------------------------------------------------------
-// Stack-allocating UpdateSubresources implementation
-template <UINT MaxSubresources>
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    UINT64 IntermediateOffset,
-    _In_range_(0,MaxSubresources) UINT FirstSubresource,
-    _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
-{
-    UINT64 RequiredSize = 0;
-    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
-    UINT NumRows[MaxSubresources];
-    UINT64 RowSizesInBytes[MaxSubresources];
-
-    const auto Desc = pDestinationResource->GetDesc();
-    ID3D12Device* pDevice = nullptr;
-    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
-    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
-    pDevice->Release();
-
-    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pSrcData);
-}
-
-//------------------------------------------------------------------------------------------------
-// Stack-allocating UpdateSubresources implementation
-template <UINT MaxSubresources>
-inline UINT64 UpdateSubresources(
-    _In_ ID3D12GraphicsCommandList* pCmdList,
-    _In_ ID3D12Resource* pDestinationResource,
-    _In_ ID3D12Resource* pIntermediate,
-    UINT64 IntermediateOffset,
-    _In_range_(0,MaxSubresources) UINT FirstSubresource,
-    _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
-    _In_ const void* pResourceData,
-    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
-{
-    UINT64 RequiredSize = 0;
-    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
-    UINT NumRows[MaxSubresources];
-    UINT64 RowSizesInBytes[MaxSubresources];
-
-    const auto Desc = pDestinationResource->GetDesc();
-    ID3D12Device* pDevice = nullptr;
-    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
-    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
-    pDevice->Release();
-
-    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pResourceData, pSrcData);
-}
-
-//------------------------------------------------------------------------------------------------
-constexpr bool D3D12IsLayoutOpaque( D3D12_TEXTURE_LAYOUT Layout ) noexcept
-{ return Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN || Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; }
-
-//------------------------------------------------------------------------------------------------
-template <typename t_CommandListType>
-inline ID3D12CommandList * const * CommandListCast(t_CommandListType * const * pp) noexcept
-{
-    // This cast is useful for passing strongly typed command list pointers into
-    // ExecuteCommandLists.
-    // This cast is valid as long as the const-ness is respected. D3D12 APIs do
-    // respect the const-ness of their arguments.
-    return reinterpret_cast<ID3D12CommandList * const *>(pp);
-}
-
-//------------------------------------------------------------------------------------------------
-// D3D12 exports a new method for serializing root signatures in the Windows 10 Anniversary Update.
-// To help enable root signature 1.1 features when they are available and not require maintaining
-// two code paths for building root signatures, this helper method reconstructs a 1.0 signature when
-// 1.1 is not supported.
-inline HRESULT D3DX12SerializeVersionedRootSignature(
-    _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc,
-    D3D_ROOT_SIGNATURE_VERSION MaxVersion,
-    _Outptr_ ID3DBlob** ppBlob,
-    _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorBlob) noexcept
-{
-    if (ppErrorBlob != nullptr)
-    {
-        *ppErrorBlob = nullptr;
-    }
-
-    switch (MaxVersion)
-    {
-        case D3D_ROOT_SIGNATURE_VERSION_1_0:
-            switch (pRootSignatureDesc->Version)
-            {
-                case D3D_ROOT_SIGNATURE_VERSION_1_0:
-                    return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);
-
-                case D3D_ROOT_SIGNATURE_VERSION_1_1:
-                {
-                    HRESULT hr = S_OK;
-                    const D3D12_ROOT_SIGNATURE_DESC1& desc_1_1 = pRootSignatureDesc->Desc_1_1;
-
-                    const SIZE_T ParametersSize = sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters;
-                    void* pParameters = (ParametersSize > 0) ? HeapAlloc(GetProcessHeap(), 0, ParametersSize) : nullptr;
-                    if (ParametersSize > 0 && pParameters == nullptr)
-                    {
-                        hr = E_OUTOFMEMORY;
-                    }
-                    auto pParameters_1_0 = static_cast<D3D12_ROOT_PARAMETER*>(pParameters);
-
-                    if (SUCCEEDED(hr))
-                    {
-                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)
-                        {
-                            __analysis_assume(ParametersSize == sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters);
-                            pParameters_1_0[n].ParameterType = desc_1_1.pParameters[n].ParameterType;
-                            pParameters_1_0[n].ShaderVisibility = desc_1_1.pParameters[n].ShaderVisibility;
-
-                            switch (desc_1_1.pParameters[n].ParameterType)
-                            {
-                            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
-                                pParameters_1_0[n].Constants.Num32BitValues = desc_1_1.pParameters[n].Constants.Num32BitValues;
-                                pParameters_1_0[n].Constants.RegisterSpace = desc_1_1.pParameters[n].Constants.RegisterSpace;
-                                pParameters_1_0[n].Constants.ShaderRegister = desc_1_1.pParameters[n].Constants.ShaderRegister;
-                                break;
-
-                            case D3D12_ROOT_PARAMETER_TYPE_CBV:
-                            case D3D12_ROOT_PARAMETER_TYPE_SRV:
-                            case D3D12_ROOT_PARAMETER_TYPE_UAV:
-                                pParameters_1_0[n].Descriptor.RegisterSpace = desc_1_1.pParameters[n].Descriptor.RegisterSpace;
-                                pParameters_1_0[n].Descriptor.ShaderRegister = desc_1_1.pParameters[n].Descriptor.ShaderRegister;
-                                break;
-
-                            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
-                                const D3D12_ROOT_DESCRIPTOR_TABLE1& table_1_1 = desc_1_1.pParameters[n].DescriptorTable;
-
-                                const SIZE_T DescriptorRangesSize = sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges;
-                                void* pDescriptorRanges = (DescriptorRangesSize > 0 && SUCCEEDED(hr)) ? HeapAlloc(GetProcessHeap(), 0, DescriptorRangesSize) : nullptr;
-                                if (DescriptorRangesSize > 0 && pDescriptorRanges == nullptr)
-                                {
-                                    hr = E_OUTOFMEMORY;
-                                }
-                                auto pDescriptorRanges_1_0 = static_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges);
-
-                                if (SUCCEEDED(hr))
-                                {
-                                    for (UINT x = 0; x < table_1_1.NumDescriptorRanges; x++)
-                                    {
-                                        __analysis_assume(DescriptorRangesSize == sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges);
-                                        pDescriptorRanges_1_0[x].BaseShaderRegister = table_1_1.pDescriptorRanges[x].BaseShaderRegister;
-                                        pDescriptorRanges_1_0[x].NumDescriptors = table_1_1.pDescriptorRanges[x].NumDescriptors;
-                                        pDescriptorRanges_1_0[x].OffsetInDescriptorsFromTableStart = table_1_1.pDescriptorRanges[x].OffsetInDescriptorsFromTableStart;
-                                        pDescriptorRanges_1_0[x].RangeType = table_1_1.pDescriptorRanges[x].RangeType;
-                                        pDescriptorRanges_1_0[x].RegisterSpace = table_1_1.pDescriptorRanges[x].RegisterSpace;
-                                    }
-                                }
-
-                                D3D12_ROOT_DESCRIPTOR_TABLE& table_1_0 = pParameters_1_0[n].DescriptorTable;
-                                table_1_0.NumDescriptorRanges = table_1_1.NumDescriptorRanges;
-                                table_1_0.pDescriptorRanges = pDescriptorRanges_1_0;
-                            }
-                        }
-                    }
-
-                    if (SUCCEEDED(hr))
-                    {
-                        const CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, desc_1_1.pStaticSamplers, desc_1_1.Flags);
-                        hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);
-                    }
-
-                    if (pParameters)
-                    {
-                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)
-                        {
-                            if (desc_1_1.pParameters[n].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
-                            {
-                                auto pDescriptorRanges_1_0 = pParameters_1_0[n].DescriptorTable.pDescriptorRanges;
-                                HeapFree(GetProcessHeap(), 0, reinterpret_cast<void*>(const_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges_1_0)));
-                            }
-                        }
-                        HeapFree(GetProcessHeap(), 0, pParameters);
-                    }
-                    return hr;
-                }
-            }
-            break;
-
-        case D3D_ROOT_SIGNATURE_VERSION_1_1:
-            return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob);
-    }
-
-    return E_INVALIDARG;
-}
-
-//------------------------------------------------------------------------------------------------
-struct CD3DX12_RT_FORMAT_ARRAY : public D3D12_RT_FORMAT_ARRAY
-{
-    CD3DX12_RT_FORMAT_ARRAY() = default;
-    explicit CD3DX12_RT_FORMAT_ARRAY(const D3D12_RT_FORMAT_ARRAY& o) noexcept
-        : D3D12_RT_FORMAT_ARRAY(o)
-    {}
-    explicit CD3DX12_RT_FORMAT_ARRAY(_In_reads_(NumFormats) const DXGI_FORMAT* pFormats, UINT NumFormats) noexcept
-    {
-        NumRenderTargets = NumFormats;
-        memcpy(RTFormats, pFormats, sizeof(RTFormats));
-        // assumes ARRAY_SIZE(pFormats) == ARRAY_SIZE(RTFormats)
-    }
-};
-
-//------------------------------------------------------------------------------------------------
-// Pipeline State Stream Helpers
-//------------------------------------------------------------------------------------------------
-
-//------------------------------------------------------------------------------------------------
-// Stream Subobjects, i.e. elements of a stream
-
-struct DefaultSampleMask { operator UINT() noexcept { return UINT_MAX; } };
-struct DefaultSampleDesc { operator DXGI_SAMPLE_DESC() noexcept { return DXGI_SAMPLE_DESC{1, 0}; } };
-
-#pragma warning(push)
-#pragma warning(disable : 4324)
-template <typename InnerStructType, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type, typename DefaultArg = InnerStructType>
-class alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT
-{
-private:
-    D3D12_PIPELINE_STATE_SUBOBJECT_TYPE pssType;
-    InnerStructType pssInner;
-public:
-    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT() noexcept : pssType(Type), pssInner(DefaultArg()) {}
-    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT(InnerStructType const& i) noexcept : pssType(Type), pssInner(i) {}
-    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT& operator=(InnerStructType const& i) noexcept { pssType = Type; pssInner = i; return *this; }
-    operator InnerStructType const&() const noexcept { return pssInner; }
-    operator InnerStructType&() noexcept { return pssInner; }
-    InnerStructType* operator&() noexcept { return &pssInner; }
-    InnerStructType const* operator&() const noexcept { return &pssInner; }
-};
-#pragma warning(pop)
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PIPELINE_STATE_FLAGS,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS>                             CD3DX12_PIPELINE_STATE_STREAM_FLAGS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK>                         CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< ID3D12RootSignature*,               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE>                    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INPUT_LAYOUT_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT>                      CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE>                CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PRIMITIVE_TOPOLOGY_TYPE,      D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY>                CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS>                                CD3DX12_PIPELINE_STATE_STREAM_VS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS>                                CD3DX12_PIPELINE_STATE_STREAM_GS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_STREAM_OUTPUT_DESC,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT>                     CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS>                                CD3DX12_PIPELINE_STATE_STREAM_HS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS>                                CD3DX12_PIPELINE_STATE_STREAM_DS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS>                                CD3DX12_PIPELINE_STATE_STREAM_PS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS>                                CD3DX12_PIPELINE_STATE_STREAM_AS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS>                                CD3DX12_PIPELINE_STATE_STREAM_MS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS>                                CD3DX12_PIPELINE_STATE_STREAM_CS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_BLEND_DESC,                 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,          CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,  CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC1,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC2,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_FORMAT,                        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT>              CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,     CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_RT_FORMAT_ARRAY,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS>             CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_SAMPLE_DESC,                   D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,    DefaultSampleDesc> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,    DefaultSampleMask> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_CACHED_PIPELINE_STATE,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO>                        CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO;
-typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_VIEW_INSTANCING_DESC,       D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, CD3DX12_DEFAULT>  CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING;
-
-//------------------------------------------------------------------------------------------------
-// Stream Parser Helpers
-
-struct ID3DX12PipelineParserCallbacks
-{
-    // Subobject Callbacks
-    virtual void FlagsCb(D3D12_PIPELINE_STATE_FLAGS) {}
-    virtual void NodeMaskCb(UINT) {}
-    virtual void RootSignatureCb(ID3D12RootSignature*) {}
-    virtual void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC&) {}
-    virtual void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE) {}
-    virtual void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE) {}
-    virtual void VSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void GSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC&) {}
-    virtual void HSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void DSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void PSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void CSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void ASCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void MSCb(const D3D12_SHADER_BYTECODE&) {}
-    virtual void BlendStateCb(const D3D12_BLEND_DESC&) {}
-    virtual void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC&) {}
-    virtual void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1&) {}
-    virtual void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2&) {}
-    virtual void DSVFormatCb(DXGI_FORMAT) {}
-    virtual void RasterizerStateCb(const D3D12_RASTERIZER_DESC&) {}
-    virtual void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY&) {}
-    virtual void SampleDescCb(const DXGI_SAMPLE_DESC&) {}
-    virtual void SampleMaskCb(UINT) {}
-    virtual void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC&) {}
-    virtual void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE&) {}
-
-    // Error Callbacks
-    virtual void ErrorBadInputParameter(UINT /*ParameterIndex*/) {}
-    virtual void ErrorDuplicateSubobject(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE /*DuplicateType*/) {}
-    virtual void ErrorUnknownSubobject(UINT /*UnknownTypeValue*/) {}
-
-    virtual ~ID3DX12PipelineParserCallbacks() = default;
-};
-
-struct D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
-{
-    ID3D12RootSignature*          pRootSignature;
-    D3D12_SHADER_BYTECODE         AS;
-    D3D12_SHADER_BYTECODE         MS;
-    D3D12_SHADER_BYTECODE         PS;
-    D3D12_BLEND_DESC              BlendState;
-    UINT                          SampleMask;
-    D3D12_RASTERIZER_DESC         RasterizerState;
-    D3D12_DEPTH_STENCIL_DESC      DepthStencilState;
-    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;
-};
-
-
-// Use CD3DX12_PIPELINE_STATE_STREAM3 for D3D12_DEPTH_STENCIL_DESC2 when CheckFeatureSupport returns true for Options14::IndependentFrontAndBackStencilSupported is true
-// Use CD3DX12_PIPELINE_STATE_STREAM2 for OS Build 19041+ (where there is a new mesh shader pipeline).
-// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
-// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
-struct CD3DX12_PIPELINE_STATE_STREAM3
-{
-    CD3DX12_PIPELINE_STATE_STREAM3() = default;
-    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
-    CD3DX12_PIPELINE_STATE_STREAM3(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , InputLayout(Desc.InputLayout)
-        , IBStripCutValue(Desc.IBStripCutValue)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , VS(Desc.VS)
-        , GS(Desc.GS)
-        , StreamOutput(Desc.StreamOutput)
-        , HS(Desc.HS)
-        , DS(Desc.DS)
-        , PS(Desc.PS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM3(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , PS(Desc.PS)
-        , AS(Desc.AS)
-        , MS(Desc.MS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM3(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
-        , CachedPSO(Desc.CachedPSO)
-    {
-        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(DepthStencilState).DepthEnable = false;
-    }
-    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
-    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
-    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
-    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
-    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
-    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
-    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
-    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
-    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
-    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
-    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
-    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
-    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
-    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
-    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
-    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2 DepthStencilState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
-    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
-    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
-    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
-    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
-    
-    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
-    {
-        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.InputLayout           = this->InputLayout;
-        D.IBStripCutValue       = this->IBStripCutValue;
-        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
-        D.VS                    = this->VS;
-        D.GS                    = this->GS;
-        D.StreamOutput          = this->StreamOutput;
-        D.HS                    = this->HS;
-        D.DS                    = this->DS;
-        D.PS                    = this->PS;
-        D.BlendState            = this->BlendState;
-        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC2(D3D12_DEPTH_STENCIL_DESC2(this->DepthStencilState));
-        D.DSVFormat             = this->DSVFormat;
-        D.RasterizerState       = this->RasterizerState;
-        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
-        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
-        D.SampleDesc            = this->SampleDesc;
-        D.SampleMask            = this->SampleMask;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
-    {
-        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.CS                    = this->CS;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-};
-
-
-// CD3DX12_PIPELINE_STATE_STREAM2 Works on OS Build 19041+ (where there is a new mesh shader pipeline).
-// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
-// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
-struct CD3DX12_PIPELINE_STATE_STREAM2
-{
-    CD3DX12_PIPELINE_STATE_STREAM2() = default;
-    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
-    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , InputLayout(Desc.InputLayout)
-        , IBStripCutValue(Desc.IBStripCutValue)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , VS(Desc.VS)
-        , GS(Desc.GS)
-        , StreamOutput(Desc.StreamOutput)
-        , HS(Desc.HS)
-        , DS(Desc.DS)
-        , PS(Desc.PS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM2(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , PS(Desc.PS)
-        , AS(Desc.AS)
-        , MS(Desc.MS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
-        , CachedPSO(Desc.CachedPSO)
-    {
-        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;
-    }
-    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
-    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
-    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
-    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
-    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
-    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
-    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
-    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
-    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
-    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
-    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
-    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
-    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
-    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
-    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
-    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
-    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
-    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
-    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
-    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
-    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
-    {
-        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.InputLayout           = this->InputLayout;
-        D.IBStripCutValue       = this->IBStripCutValue;
-        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
-        D.VS                    = this->VS;
-        D.GS                    = this->GS;
-        D.StreamOutput          = this->StreamOutput;
-        D.HS                    = this->HS;
-        D.DS                    = this->DS;
-        D.PS                    = this->PS;
-        D.BlendState            = this->BlendState;
-        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
-        D.DSVFormat             = this->DSVFormat;
-        D.RasterizerState       = this->RasterizerState;
-        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
-        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
-        D.SampleDesc            = this->SampleDesc;
-        D.SampleMask            = this->SampleMask;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
-    {
-        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.CS                    = this->CS;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-};
-
-// CD3DX12_PIPELINE_STATE_STREAM1 Works on OS Build 16299+ (where there is a new view instancing subobject).
-// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
-struct CD3DX12_PIPELINE_STATE_STREAM1
-{
-    CD3DX12_PIPELINE_STATE_STREAM1() = default;
-    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
-    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , InputLayout(Desc.InputLayout)
-        , IBStripCutValue(Desc.IBStripCutValue)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , VS(Desc.VS)
-        , GS(Desc.GS)
-        , StreamOutput(Desc.StreamOutput)
-        , HS(Desc.HS)
-        , DS(Desc.DS)
-        , PS(Desc.PS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM1(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , PS(Desc.PS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
-        , CachedPSO(Desc.CachedPSO)
-    {
-        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;
-    }
-    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
-    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
-    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
-    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
-    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
-    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
-    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
-    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
-    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
-    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
-    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
-    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
-    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
-    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
-    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
-    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
-    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
-    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
-    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
-    {
-        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.InputLayout           = this->InputLayout;
-        D.IBStripCutValue       = this->IBStripCutValue;
-        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
-        D.VS                    = this->VS;
-        D.GS                    = this->GS;
-        D.StreamOutput          = this->StreamOutput;
-        D.HS                    = this->HS;
-        D.DS                    = this->DS;
-        D.PS                    = this->PS;
-        D.BlendState            = this->BlendState;
-        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
-        D.DSVFormat             = this->DSVFormat;
-        D.RasterizerState       = this->RasterizerState;
-        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
-        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
-        D.SampleDesc            = this->SampleDesc;
-        D.SampleMask            = this->SampleMask;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
-    {
-        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.CS                    = this->CS;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-};
-
-
-struct CD3DX12_PIPELINE_MESH_STATE_STREAM
-{
-    CD3DX12_PIPELINE_MESH_STATE_STREAM() = default;
-    CD3DX12_PIPELINE_MESH_STATE_STREAM(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , PS(Desc.PS)
-        , AS(Desc.AS)
-        , MS(Desc.MS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
-    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
-    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
-    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
-    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
-    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
-    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
-    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
-    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
-    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
-    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
-    D3DX12_MESH_SHADER_PIPELINE_STATE_DESC MeshShaderDescV0() const noexcept
-    {
-        D3DX12_MESH_SHADER_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.PS                    = this->PS;
-        D.AS                    = this->AS;
-        D.MS                    = this->MS;
-        D.BlendState            = this->BlendState;
-        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
-        D.DSVFormat             = this->DSVFormat;
-        D.RasterizerState       = this->RasterizerState;
-        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
-        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
-        D.SampleDesc            = this->SampleDesc;
-        D.SampleMask            = this->SampleMask;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-};
-
-// CD3DX12_PIPELINE_STATE_STREAM works on OS Build 15063+ but does not support new subobject(s) added in OS Build 16299+.
-// See CD3DX12_PIPELINE_STATE_STREAM1 for instance.
-struct CD3DX12_PIPELINE_STATE_STREAM
-{
-    CD3DX12_PIPELINE_STATE_STREAM() = default;
-    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , InputLayout(Desc.InputLayout)
-        , IBStripCutValue(Desc.IBStripCutValue)
-        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
-        , VS(Desc.VS)
-        , GS(Desc.GS)
-        , StreamOutput(Desc.StreamOutput)
-        , HS(Desc.HS)
-        , DS(Desc.DS)
-        , PS(Desc.PS)
-        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
-        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
-        , DSVFormat(Desc.DSVFormat)
-        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
-        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
-        , SampleDesc(Desc.SampleDesc)
-        , SampleMask(Desc.SampleMask)
-        , CachedPSO(Desc.CachedPSO)
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
-        : Flags(Desc.Flags)
-        , NodeMask(Desc.NodeMask)
-        , pRootSignature(Desc.pRootSignature)
-        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
-        , CachedPSO(Desc.CachedPSO)
-    {}
-    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
-    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
-    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
-    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
-    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
-    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
-    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
-    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
-    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
-    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
-    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
-    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
-    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
-    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
-    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
-    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
-    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
-    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
-    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
-    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
-    {
-        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.InputLayout           = this->InputLayout;
-        D.IBStripCutValue       = this->IBStripCutValue;
-        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
-        D.VS                    = this->VS;
-        D.GS                    = this->GS;
-        D.StreamOutput          = this->StreamOutput;
-        D.HS                    = this->HS;
-        D.DS                    = this->DS;
-        D.PS                    = this->PS;
-        D.BlendState            = this->BlendState;
-        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
-        D.DSVFormat             = this->DSVFormat;
-        D.RasterizerState       = this->RasterizerState;
-        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
-        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
-        D.SampleDesc            = this->SampleDesc;
-        D.SampleMask            = this->SampleMask;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
-    {
-        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
-        D.Flags                 = this->Flags;
-        D.NodeMask              = this->NodeMask;
-        D.pRootSignature        = this->pRootSignature;
-        D.CS                    = this->CS;
-        D.CachedPSO             = this->CachedPSO;
-        return D;
-    }
-};
-
-struct CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
-{
-    CD3DX12_PIPELINE_STATE_STREAM2 PipelineStream;
-    CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER() noexcept
-        : SeenDSS(false)
-    {
-        // Adjust defaults to account for absent members.
-        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
-
-        // Depth disabled if no DSV format specified.
-        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;
-    }
-
-    // ID3DX12PipelineParserCallbacks
-    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}
-    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}
-    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}
-    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}
-    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}
-    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}
-    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}
-    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}
-    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}
-    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}
-    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}
-    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}
-    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}
-    void ASCb(const D3D12_SHADER_BYTECODE& AS) override {PipelineStream.AS = AS;}
-    void MSCb(const D3D12_SHADER_BYTECODE& MS) override {PipelineStream.MS = MS;}
-    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}
-    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
-    {
-        PipelineStream.DSVFormat = DSVFormat;
-        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
-        {
-            // Re-enable depth for the default state.
-            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;
-        }
-    }
-    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}
-    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}
-    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}
-    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}
-    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}
-    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}
-
-private:
-    bool SeenDSS;
-};
-
-
-struct CD3DX12_PIPELINE_STATE_STREAM3_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
-{
-    CD3DX12_PIPELINE_STATE_STREAM3 PipelineStream;
-    CD3DX12_PIPELINE_STATE_STREAM3_PARSE_HELPER() noexcept
-        : SeenDSS(false)
-    {
-        // Adjust defaults to account for absent members.
-        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
-
-        // Depth disabled if no DSV format specified.
-        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = false;
-    }
-
-    // ID3DX12PipelineParserCallbacks
-    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override { PipelineStream.Flags = Flags; }
-    void NodeMaskCb(UINT NodeMask) override { PipelineStream.NodeMask = NodeMask; }
-    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override { PipelineStream.pRootSignature = pRootSignature; }
-    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override { PipelineStream.InputLayout = InputLayout; }
-    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override { PipelineStream.IBStripCutValue = IBStripCutValue; }
-    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override { PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType; }
-    void VSCb(const D3D12_SHADER_BYTECODE& VS) override { PipelineStream.VS = VS; }
-    void GSCb(const D3D12_SHADER_BYTECODE& GS) override { PipelineStream.GS = GS; }
-    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override { PipelineStream.StreamOutput = StreamOutput; }
-    void HSCb(const D3D12_SHADER_BYTECODE& HS) override { PipelineStream.HS = HS; }
-    void DSCb(const D3D12_SHADER_BYTECODE& DS) override { PipelineStream.DS = DS; }
-    void PSCb(const D3D12_SHADER_BYTECODE& PS) override { PipelineStream.PS = PS; }
-    void CSCb(const D3D12_SHADER_BYTECODE& CS) override { PipelineStream.CS = CS; }
-    void ASCb(const D3D12_SHADER_BYTECODE& AS) override { PipelineStream.AS = AS; }
-    void MSCb(const D3D12_SHADER_BYTECODE& MS) override { PipelineStream.MS = MS; }
-    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override { PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState); }
-    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
-    {
-        PipelineStream.DSVFormat = DSVFormat;
-        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
-        {
-            // Re-enable depth for the default state.
-            static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = true;
-        }
-    }
-    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState); }
-    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override { PipelineStream.RTVFormats = RTVFormats; }
-    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override { PipelineStream.SampleDesc = SampleDesc; }
-    void SampleMaskCb(UINT SampleMask) override { PipelineStream.SampleMask = SampleMask; }
-    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override { PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc); }
-    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override { PipelineStream.CachedPSO = CachedPSO; }
-
-private:
-    bool SeenDSS;
-};
-
-struct CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
-{
-    CD3DX12_PIPELINE_STATE_STREAM1 PipelineStream;
-    CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER() noexcept
-        : SeenDSS(false)
-    {
-        // Adjust defaults to account for absent members.
-        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
-
-        // Depth disabled if no DSV format specified.
-        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;
-    }
-
-    // ID3DX12PipelineParserCallbacks
-    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}
-    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}
-    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}
-    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}
-    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}
-    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}
-    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}
-    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}
-    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}
-    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}
-    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}
-    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}
-    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}
-    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}
-    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
-    {
-        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
-        SeenDSS = true;
-    }
-    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
-    {
-        PipelineStream.DSVFormat = DSVFormat;
-        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
-        {
-            // Re-enable depth for the default state.
-            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;
-        }
-    }
-    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}
-    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}
-    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}
-    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}
-    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}
-    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}
-
-private:
-    bool SeenDSS;
-};
-
-inline D3D12_PIPELINE_STATE_SUBOBJECT_TYPE D3DX12GetBaseSubobjectType(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE SubobjectType) noexcept
-{
-    switch (SubobjectType)
-    {
-    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:
-        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;
-    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2:
-        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;
-    default:
-        return SubobjectType;
-    }
-}
-
-inline HRESULT D3DX12ParsePipelineStream(const D3D12_PIPELINE_STATE_STREAM_DESC& Desc, ID3DX12PipelineParserCallbacks* pCallbacks)
-{
-    if (pCallbacks == nullptr)
-    {
-        return E_INVALIDARG;
-    }
-
-    if (Desc.SizeInBytes == 0 || Desc.pPipelineStateSubobjectStream == nullptr)
-    {
-        pCallbacks->ErrorBadInputParameter(1); // first parameter issue
-        return E_INVALIDARG;
-    }
-
-    bool SubobjectSeen[D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID] = {};
-    for (SIZE_T CurOffset = 0, SizeOfSubobject = 0; CurOffset < Desc.SizeInBytes; CurOffset += SizeOfSubobject)
-    {
-        BYTE* pStream = static_cast<BYTE*>(Desc.pPipelineStateSubobjectStream)+CurOffset;
-        auto SubobjectType = *reinterpret_cast<D3D12_PIPELINE_STATE_SUBOBJECT_TYPE*>(pStream);
-        if (SubobjectType < 0 || SubobjectType >= D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID)
-        {
-            pCallbacks->ErrorUnknownSubobject(SubobjectType);
-            return E_INVALIDARG;
-        }
-        if (SubobjectSeen[D3DX12GetBaseSubobjectType(SubobjectType)])
-        {
-            pCallbacks->ErrorDuplicateSubobject(SubobjectType);
-            return E_INVALIDARG; // disallow subobject duplicates in a stream
-        }
-        SubobjectSeen[SubobjectType] = true;
-        switch (SubobjectType)
-        {
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE:
-            pCallbacks->RootSignatureCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS:
-            pCallbacks->VSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::VS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS:
-            pCallbacks->PSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS:
-            pCallbacks->DSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS:
-            pCallbacks->HSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::HS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS:
-            pCallbacks->GSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::GS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS:
-            pCallbacks->CSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS:
-            pCallbacks->ASCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::AS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS:
-            pCallbacks->MSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::MS)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT:
-            pCallbacks->StreamOutputCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND:
-            pCallbacks->BlendStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::BlendState)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK:
-            pCallbacks->SampleMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleMask)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER:
-            pCallbacks->RasterizerStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL:
-            pCallbacks->DepthStencilStateCb(*reinterpret_cast<CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:
-            pCallbacks->DepthStencilState1Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2:
-            pCallbacks->DepthStencilState2Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT:
-            pCallbacks->InputLayoutCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::InputLayout)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE:
-            pCallbacks->IBStripCutValueCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY:
-            pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS:
-            pCallbacks->RTVFormatsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT:
-            pCallbacks->DSVFormatCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC:
-            pCallbacks->SampleDescCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK:
-            pCallbacks->NodeMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::NodeMask)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO:
-            pCallbacks->CachedPSOCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS:
-            pCallbacks->FlagsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::Flags)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags);
-            break;
-        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING:
-            pCallbacks->ViewInstancingCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc)*>(pStream));
-            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc);
-            break;
-        default:
-            pCallbacks->ErrorUnknownSubobject(SubobjectType);
-            return E_INVALIDARG;
-        }
-    }
-
-    return S_OK;
-}
-
-//------------------------------------------------------------------------------------------------
-inline bool operator==( const D3D12_CLEAR_VALUE &a, const D3D12_CLEAR_VALUE &b) noexcept
-{
-    if (a.Format != b.Format) return false;
-    if (a.Format == DXGI_FORMAT_D24_UNORM_S8_UINT
-     || a.Format == DXGI_FORMAT_D16_UNORM
-     || a.Format == DXGI_FORMAT_D32_FLOAT
-     || a.Format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
-    {
-        return (a.DepthStencil.Depth == b.DepthStencil.Depth) &&
-          (a.DepthStencil.Stencil == b.DepthStencil.Stencil);
-    } else {
-        return (a.Color[0] == b.Color[0]) &&
-               (a.Color[1] == b.Color[1]) &&
-               (a.Color[2] == b.Color[2]) &&
-               (a.Color[3] == b.Color[3]);
-    }
-}
-inline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &b) noexcept
-{
-    return a.ClearValue == b.ClearValue;
-}
-inline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &a, const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &b) noexcept
-{
-    if (a.pSrcResource != b.pSrcResource) return false;
-    if (a.pDstResource != b.pDstResource) return false;
-    if (a.SubresourceCount != b.SubresourceCount) return false;
-    if (a.Format != b.Format) return false;
-    if (a.ResolveMode != b.ResolveMode) return false;
-    if (a.PreserveResolveSource != b.PreserveResolveSource) return false;
-    return true;
-}
-inline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS &b) noexcept
-{
-    if (a.Type != b.Type) return false;
-    if (a.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR && !(a.Clear == b.Clear)) return false;
-    return true;
-}
-inline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS &a, const D3D12_RENDER_PASS_ENDING_ACCESS &b) noexcept
-{
-    if (a.Type != b.Type) return false;
-    if (a.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE && !(a.Resolve == b.Resolve)) return false;
-    return true;
-}
-inline bool operator==( const D3D12_RENDER_PASS_RENDER_TARGET_DESC &a, const D3D12_RENDER_PASS_RENDER_TARGET_DESC &b) noexcept
-{
-    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;
-    if (!(a.BeginningAccess == b.BeginningAccess)) return false;
-    if (!(a.EndingAccess == b.EndingAccess)) return false;
-    return true;
-}
-inline bool operator==( const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &a, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &b) noexcept
-{
-    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;
-    if (!(a.DepthBeginningAccess == b.DepthBeginningAccess)) return false;
-    if (!(a.StencilBeginningAccess == b.StencilBeginningAccess)) return false;
-    if (!(a.DepthEndingAccess == b.DepthEndingAccess)) return false;
-    if (!(a.StencilEndingAccess == b.StencilEndingAccess)) return false;
-    return true;
-}
-
-
-#ifndef D3DX12_NO_STATE_OBJECT_HELPERS
-
-//================================================================================================
-// D3DX12 State Object Creation Helpers
-//
-// Helper classes for creating new style state objects out of an arbitrary set of subobjects.
-// Uses STL
-//
-// Start by instantiating CD3DX12_STATE_OBJECT_DESC (see its public methods).
-// One of its methods is CreateSubobject(), which has a comment showing a couple of options for
-// defining subobjects using the helper classes for each subobject (CD3DX12_DXIL_LIBRARY_SUBOBJECT
-// etc.). The subobject helpers each have methods specific to the subobject for configuring its
-// contents.
-//
-//================================================================================================
-#include <list>
-#include <memory>
-#include <string>
-#include <vector>
-#ifndef D3DX12_USE_ATL
-#include <wrl/client.h>
-#define D3DX12_COM_PTR Microsoft::WRL::ComPtr
-#define D3DX12_COM_PTR_GET(x) x.Get()
-#define D3DX12_COM_PTR_ADDRESSOF(x) x.GetAddressOf()
-#else
-#include <atlbase.h>
-#define D3DX12_COM_PTR ATL::CComPtr
-#define D3DX12_COM_PTR_GET(x) x.p
-#define D3DX12_COM_PTR_ADDRESSOF(x) &x.p
-#endif
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_STATE_OBJECT_DESC
-{
-public:
-    CD3DX12_STATE_OBJECT_DESC() noexcept
-    {
-        Init(D3D12_STATE_OBJECT_TYPE_COLLECTION);
-    }
-    CD3DX12_STATE_OBJECT_DESC(D3D12_STATE_OBJECT_TYPE Type) noexcept
-    {
-        Init(Type);
-    }
-    void SetStateObjectType(D3D12_STATE_OBJECT_TYPE Type) noexcept { m_Desc.Type = Type; }
-    operator const D3D12_STATE_OBJECT_DESC&()
-    {
-        // Do final preparation work
-        m_RepointedAssociations.clear();
-        m_SubobjectArray.clear();
-        m_SubobjectArray.reserve(m_Desc.NumSubobjects);
-        // Flatten subobjects into an array (each flattened subobject still has a
-        // member that's a pointer to its desc that's not flattened)
-        for (auto Iter = m_SubobjectList.begin();
-            Iter != m_SubobjectList.end(); Iter++)
-        {
-            m_SubobjectArray.push_back(*Iter);
-            // Store new location in array so we can redirect pointers contained in subobjects
-            Iter->pSubobjectArrayLocation = &m_SubobjectArray.back();
-        }
-        // For subobjects with pointer fields, create a new copy of those subobject definitions
-        // with fixed pointers
-        for (UINT i = 0; i < m_Desc.NumSubobjects; i++)
-        {
-            if (m_SubobjectArray[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
-            {
-                auto pOriginalSubobjectAssociation =
-                    static_cast<const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION*>(m_SubobjectArray[i].pDesc);
-                D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation;
-                auto pWrapper =
-                    static_cast<const SUBOBJECT_WRAPPER*>(pOriginalSubobjectAssociation->pSubobjectToAssociate);
-                Repointed.pSubobjectToAssociate = pWrapper->pSubobjectArrayLocation;
-                m_RepointedAssociations.push_back(Repointed);
-                m_SubobjectArray[i].pDesc = &m_RepointedAssociations.back();
-            }
-        }
-        // Below: using ugly way to get pointer in case .data() is not defined
-        m_Desc.pSubobjects = m_Desc.NumSubobjects ? &m_SubobjectArray[0] : nullptr;
-        return m_Desc;
-    }
-    operator const D3D12_STATE_OBJECT_DESC*()
-    {
-        // Cast calls the above final preparation work
-        return &static_cast<const D3D12_STATE_OBJECT_DESC&>(*this);
-    }
-
-    // CreateSubobject creates a sububject helper (e.g. CD3DX12_HIT_GROUP_SUBOBJECT)
-    // whose lifetime is owned by this class.
-    // e.g.
-    //
-    //    CD3DX12_STATE_OBJECT_DESC Collection1(D3D12_STATE_OBJECT_TYPE_COLLECTION);
-    //    auto Lib0 = Collection1.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>();
-    //    Lib0->SetDXILLibrary(&pMyAppDxilLibs[0]);
-    //    Lib0->DefineExport(L"rayGenShader0"); // in practice these export listings might be
-    //                                          // data/engine driven
-    //    etc.
-    //
-    // Alternatively, users can instantiate sububject helpers explicitly, such as via local
-    // variables instead, passing the state object desc that should point to it into the helper
-    // constructor (or call mySubobjectHelper.AddToStateObject(Collection1)).
-    // In this alternative scenario, the user must keep the subobject alive as long as the state
-    // object it is associated with is alive, else its pointer references will be stale.
-    // e.g.
-    //
-    //    CD3DX12_STATE_OBJECT_DESC RaytracingState2(D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);
-    //    CD3DX12_DXIL_LIBRARY_SUBOBJECT LibA(RaytracingState2);
-    //    LibA.SetDXILLibrary(&pMyAppDxilLibs[4]); // not manually specifying exports
-    //                                             // - meaning all exports in the libraries
-    //                                             // are exported
-    //    etc.
-
-    template<typename T>
-    T* CreateSubobject()
-    {
-        T* pSubobject = new T(*this);
-        m_OwnedSubobjectHelpers.emplace_back(pSubobject);
-        return pSubobject;
-    }
-
-private:
-    D3D12_STATE_SUBOBJECT* TrackSubobject(D3D12_STATE_SUBOBJECT_TYPE Type, void* pDesc)
-    {
-        SUBOBJECT_WRAPPER Subobject;
-        Subobject.pSubobjectArrayLocation = nullptr;
-        Subobject.Type = Type;
-        Subobject.pDesc = pDesc;
-        m_SubobjectList.push_back(Subobject);
-        m_Desc.NumSubobjects++;
-        return &m_SubobjectList.back();
-    }
-    void Init(D3D12_STATE_OBJECT_TYPE Type) noexcept
-    {
-        SetStateObjectType(Type);
-        m_Desc.pSubobjects = nullptr;
-        m_Desc.NumSubobjects = 0;
-        m_SubobjectList.clear();
-        m_SubobjectArray.clear();
-        m_RepointedAssociations.clear();
-    }
-    typedef struct SUBOBJECT_WRAPPER : public D3D12_STATE_SUBOBJECT
-    {
-        D3D12_STATE_SUBOBJECT* pSubobjectArrayLocation; // new location when flattened into array
-                                                        // for repointing pointers in subobjects
-    } SUBOBJECT_WRAPPER;
-    D3D12_STATE_OBJECT_DESC m_Desc;
-    std::list<SUBOBJECT_WRAPPER>   m_SubobjectList; // Pointers to list nodes handed out so
-                                                    // these can be edited live
-    std::vector<D3D12_STATE_SUBOBJECT> m_SubobjectArray; // Built at the end, copying list contents
-
-    std::list<D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION>
-            m_RepointedAssociations; // subobject type that contains pointers to other subobjects,
-                                     // repointed to flattened array
-
-    class StringContainer
-    {
-    public:
-        LPCWSTR LocalCopy(LPCWSTR string, bool bSingleString = false)
-        {
-            if (string)
-            {
-                if (bSingleString)
-                {
-                    m_Strings.clear();
-                    m_Strings.push_back(string);
-                }
-                else
-                {
-                    m_Strings.push_back(string);
-                }
-                return m_Strings.back().c_str();
-            }
-            else
-            {
-                return nullptr;
-            }
-        }
-        void clear() noexcept { m_Strings.clear(); }
-    private:
-        std::list<std::wstring> m_Strings;
-    };
-
-    class SUBOBJECT_HELPER_BASE
-    {
-    public:
-        SUBOBJECT_HELPER_BASE() noexcept { Init(); }
-        virtual ~SUBOBJECT_HELPER_BASE() = default;
-        virtual D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept = 0;
-        void AddToStateObject(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-        {
-            m_pSubobject = ContainingStateObject.TrackSubobject(Type(), Data());
-        }
-    protected:
-        virtual void* Data() noexcept = 0;
-        void Init() noexcept { m_pSubobject = nullptr; }
-        D3D12_STATE_SUBOBJECT* m_pSubobject;
-    };
-
-#if(__cplusplus >= 201103L)
-    std::list<std::unique_ptr<const SUBOBJECT_HELPER_BASE>> m_OwnedSubobjectHelpers;
-#else
-    class OWNED_HELPER
-    {
-    public:
-        OWNED_HELPER(const SUBOBJECT_HELPER_BASE* pHelper) noexcept { m_pHelper = pHelper; }
-        ~OWNED_HELPER() { delete m_pHelper; }
-        const SUBOBJECT_HELPER_BASE* m_pHelper;
-    };
-
-    std::list<OWNED_HELPER> m_OwnedSubobjectHelpers;
-#endif
-
-    friend class CD3DX12_DXIL_LIBRARY_SUBOBJECT;
-    friend class CD3DX12_EXISTING_COLLECTION_SUBOBJECT;
-    friend class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT;
-    friend class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
-    friend class CD3DX12_HIT_GROUP_SUBOBJECT;
-    friend class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT;
-    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT;
-    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT;
-    friend class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT;
-    friend class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT;
-    friend class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT;
-    friend class CD3DX12_NODE_MASK_SUBOBJECT;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_DXIL_LIBRARY_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_DXIL_LIBRARY_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_DXIL_LIBRARY_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetDXILLibrary(const D3D12_SHADER_BYTECODE* pCode) noexcept
-    {
-        static const D3D12_SHADER_BYTECODE Default = {};
-        m_Desc.DXILLibrary = pCode ? *pCode : Default;
-    }
-    void DefineExport(
-        LPCWSTR Name,
-        LPCWSTR ExportToRename = nullptr,
-        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)
-    {
-        D3D12_EXPORT_DESC Export;
-        Export.Name = m_Strings.LocalCopy(Name);
-        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);
-        Export.Flags = Flags;
-        m_Exports.push_back(Export);
-        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
-        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());
-    }
-    template<size_t N>
-    void DefineExports(LPCWSTR(&Exports)[N])
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            DefineExport(Exports[i]);
-        }
-    }
-    void DefineExports(const LPCWSTR* Exports, UINT N)
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            DefineExport(Exports[i]);
-        }
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_DXIL_LIBRARY_DESC&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-        m_Strings.clear();
-        m_Exports.clear();
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_DXIL_LIBRARY_DESC m_Desc;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
-    std::vector<D3D12_EXPORT_DESC> m_Exports;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_EXISTING_COLLECTION_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_EXISTING_COLLECTION_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_EXISTING_COLLECTION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetExistingCollection(ID3D12StateObject*pExistingCollection) noexcept
-    {
-        m_Desc.pExistingCollection = pExistingCollection;
-        m_CollectionRef = pExistingCollection;
-    }
-    void DefineExport(
-        LPCWSTR Name,
-        LPCWSTR ExportToRename = nullptr,
-        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)
-    {
-        D3D12_EXPORT_DESC Export;
-        Export.Name = m_Strings.LocalCopy(Name);
-        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);
-        Export.Flags = Flags;
-        m_Exports.push_back(Export);
-        m_Desc.pExports = &m_Exports[0]; // using ugly way to get pointer in case .data() is not defined
-        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());
-    }
-    template<size_t N>
-    void DefineExports(LPCWSTR(&Exports)[N])
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            DefineExport(Exports[i]);
-        }
-    }
-    void DefineExports(const LPCWSTR* Exports, UINT N)
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            DefineExport(Exports[i]);
-        }
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_EXISTING_COLLECTION_DESC&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-        m_CollectionRef = nullptr;
-        m_Strings.clear();
-        m_Exports.clear();
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_EXISTING_COLLECTION_DESC m_Desc;
-    D3DX12_COM_PTR<ID3D12StateObject> m_CollectionRef;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
-    std::vector<D3D12_EXPORT_DESC> m_Exports;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetSubobjectToAssociate(const D3D12_STATE_SUBOBJECT& SubobjectToAssociate) noexcept
-    {
-        m_Desc.pSubobjectToAssociate = &SubobjectToAssociate;
-    }
-    void AddExport(LPCWSTR Export)
-    {
-        m_Desc.NumExports++;
-        m_Exports.push_back(m_Strings.LocalCopy(Export));
-        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
-    }
-    template<size_t N>
-    void AddExports(LPCWSTR (&Exports)[N])
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            AddExport(Exports[i]);
-        }
-    }
-    void AddExports(const LPCWSTR* Exports, UINT N)
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            AddExport(Exports[i]);
-        }
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-        m_Strings.clear();
-        m_Exports.clear();
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
-    std::vector<LPCWSTR> m_Exports;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION() noexcept
-    {
-        Init();
-    }
-    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetSubobjectNameToAssociate(LPCWSTR SubobjectToAssociate)
-    {
-        m_Desc.SubobjectToAssociate = m_SubobjectName.LocalCopy(SubobjectToAssociate, true);
-    }
-    void AddExport(LPCWSTR Export)
-    {
-        m_Desc.NumExports++;
-        m_Exports.push_back(m_Strings.LocalCopy(Export));
-        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
-    }
-    template<size_t N>
-    void AddExports(LPCWSTR (&Exports)[N])
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            AddExport(Exports[i]);
-        }
-    }
-    void AddExports(const LPCWSTR* Exports, UINT N)
-    {
-        for (UINT i = 0; i < N; i++)
-        {
-            AddExport(Exports[i]);
-        }
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-        m_Strings.clear();
-        m_SubobjectName.clear();
-        m_Exports.clear();
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer m_SubobjectName;
-    std::vector<LPCWSTR> m_Exports;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_HIT_GROUP_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_HIT_GROUP_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_HIT_GROUP_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetHitGroupExport(LPCWSTR exportName)
-    {
-        m_Desc.HitGroupExport = m_Strings[0].LocalCopy(exportName, true);
-    }
-    void SetHitGroupType(D3D12_HIT_GROUP_TYPE Type) noexcept { m_Desc.Type = Type; }
-    void SetAnyHitShaderImport(LPCWSTR importName)
-    {
-        m_Desc.AnyHitShaderImport = m_Strings[1].LocalCopy(importName, true);
-    }
-    void SetClosestHitShaderImport(LPCWSTR importName)
-    {
-        m_Desc.ClosestHitShaderImport = m_Strings[2].LocalCopy(importName, true);
-    }
-    void SetIntersectionShaderImport(LPCWSTR importName)
-    {
-        m_Desc.IntersectionShaderImport = m_Strings[3].LocalCopy(importName, true);
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_HIT_GROUP_DESC&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-        for (UINT i = 0; i < m_NumStrings; i++)
-        {
-            m_Strings[i].clear();
-        }
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_HIT_GROUP_DESC m_Desc;
-    static constexpr UINT m_NumStrings = 4;
-    CD3DX12_STATE_OBJECT_DESC::StringContainer
-        m_Strings[m_NumStrings]; // one string for every entrypoint name
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void Config(UINT MaxPayloadSizeInBytes, UINT MaxAttributeSizeInBytes) noexcept
-    {
-        m_Desc.MaxPayloadSizeInBytes = MaxPayloadSizeInBytes;
-        m_Desc.MaxAttributeSizeInBytes = MaxAttributeSizeInBytes;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_RAYTRACING_SHADER_CONFIG&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_RAYTRACING_SHADER_CONFIG m_Desc;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void Config(UINT MaxTraceRecursionDepth) noexcept
-    {
-        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_RAYTRACING_PIPELINE_CONFIG&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_RAYTRACING_PIPELINE_CONFIG m_Desc;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void Config(UINT MaxTraceRecursionDepth, D3D12_RAYTRACING_PIPELINE_FLAGS Flags) noexcept
-    {
-        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;
-        m_Desc.Flags = Flags;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_RAYTRACING_PIPELINE_CONFIG1&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_RAYTRACING_PIPELINE_CONFIG1 m_Desc;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept
-    {
-        m_pRootSig = pRootSig;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator ID3D12RootSignature*() const noexcept { return D3DX12_COM_PTR_GET(m_pRootSig); }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_pRootSig = nullptr;
-    }
-    void* Data() noexcept override { return D3DX12_COM_PTR_ADDRESSOF(m_pRootSig); }
-    D3DX12_COM_PTR<ID3D12RootSignature> m_pRootSig;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept
-    {
-        m_pRootSig = pRootSig;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator ID3D12RootSignature*() const noexcept { return D3DX12_COM_PTR_GET(m_pRootSig); }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_pRootSig = nullptr;
-    }
-    void* Data() noexcept override { return D3DX12_COM_PTR_ADDRESSOF(m_pRootSig); }
-    D3DX12_COM_PTR<ID3D12RootSignature> m_pRootSig;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetFlags(D3D12_STATE_OBJECT_FLAGS Flags) noexcept
-    {
-        m_Desc.Flags = Flags;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_STATE_OBJECT_CONFIG&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_STATE_OBJECT_CONFIG m_Desc;
-};
-
-//------------------------------------------------------------------------------------------------
-class CD3DX12_NODE_MASK_SUBOBJECT
-    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
-{
-public:
-    CD3DX12_NODE_MASK_SUBOBJECT() noexcept
-    {
-        Init();
-    }
-    CD3DX12_NODE_MASK_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
-    {
-        Init();
-        AddToStateObject(ContainingStateObject);
-    }
-    void SetNodeMask(UINT NodeMask) noexcept
-    {
-        m_Desc.NodeMask = NodeMask;
-    }
-    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
-    {
-        return D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK;
-    }
-    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
-    operator const D3D12_NODE_MASK&() const noexcept { return m_Desc; }
-private:
-    void Init() noexcept
-    {
-        SUBOBJECT_HELPER_BASE::Init();
-        m_Desc = {};
-    }
-    void* Data() noexcept override { return &m_Desc; }
-    D3D12_NODE_MASK m_Desc;
-};
-
-#endif // !D3DX12_NO_STATE_OBJECT_HELPERS
-
-
-//================================================================================================
-// D3DX12 Enhanced Barrier Helpers
-//================================================================================================
-
-class CD3DX12_BARRIER_SUBRESOURCE_RANGE : public D3D12_BARRIER_SUBRESOURCE_RANGE
-{
-public:
-    CD3DX12_BARRIER_SUBRESOURCE_RANGE() = default;
-    CD3DX12_BARRIER_SUBRESOURCE_RANGE(const D3D12_BARRIER_SUBRESOURCE_RANGE &o) noexcept :
-        D3D12_BARRIER_SUBRESOURCE_RANGE(o)
-    {}
-    explicit CD3DX12_BARRIER_SUBRESOURCE_RANGE(UINT Subresource) noexcept :
-        D3D12_BARRIER_SUBRESOURCE_RANGE{ Subresource, 0, 0, 0, 0, 0 }
-    {}
-    CD3DX12_BARRIER_SUBRESOURCE_RANGE(
-        UINT FirstMipLevel,
-        UINT NumMips,
-        UINT FirstArraySlice,
-        UINT NumArraySlices,
-        UINT FirstPlane = 0,
-        UINT NumPlanes = 1) noexcept :
-        D3D12_BARRIER_SUBRESOURCE_RANGE
-        {
-            FirstMipLevel,
-            NumMips,
-            FirstArraySlice,
-            NumArraySlices,
-            FirstPlane,
-            NumPlanes
-        }
-    {}
-};
-
-class CD3DX12_GLOBAL_BARRIER : public D3D12_GLOBAL_BARRIER
-{
-public:
-    CD3DX12_GLOBAL_BARRIER() = default;
-    CD3DX12_GLOBAL_BARRIER(const D3D12_GLOBAL_BARRIER &o) noexcept : D3D12_GLOBAL_BARRIER(o){}
-    CD3DX12_GLOBAL_BARRIER(
-        D3D12_BARRIER_SYNC syncBefore,
-        D3D12_BARRIER_SYNC syncAfter,
-        D3D12_BARRIER_ACCESS accessBefore,
-        D3D12_BARRIER_ACCESS accessAfter) noexcept : D3D12_GLOBAL_BARRIER {
-            syncBefore,
-            syncAfter,
-            accessBefore,
-            accessAfter
-        }
-    {}
-};
-
-class CD3DX12_BUFFER_BARRIER : public D3D12_BUFFER_BARRIER
-{
-public:
-    CD3DX12_BUFFER_BARRIER() = default;
-    CD3DX12_BUFFER_BARRIER(const D3D12_BUFFER_BARRIER &o) noexcept : D3D12_BUFFER_BARRIER(o){}
-    CD3DX12_BUFFER_BARRIER(
-        D3D12_BARRIER_SYNC syncBefore,
-        D3D12_BARRIER_SYNC syncAfter,
-        D3D12_BARRIER_ACCESS accessBefore,
-        D3D12_BARRIER_ACCESS accessAfter,
-        ID3D12Resource *pRes) noexcept : D3D12_BUFFER_BARRIER {
-            syncBefore,
-            syncAfter,
-            accessBefore,
-            accessAfter,
-            pRes,
-            0, ULLONG_MAX
-        }
-    {}
-};
-
-class CD3DX12_TEXTURE_BARRIER : public D3D12_TEXTURE_BARRIER
-{
-public:
-    CD3DX12_TEXTURE_BARRIER() = default;
-    CD3DX12_TEXTURE_BARRIER(const D3D12_TEXTURE_BARRIER &o) noexcept : D3D12_TEXTURE_BARRIER(o){}
-    CD3DX12_TEXTURE_BARRIER(
-        D3D12_BARRIER_SYNC syncBefore,
-        D3D12_BARRIER_SYNC syncAfter,
-        D3D12_BARRIER_ACCESS accessBefore,
-        D3D12_BARRIER_ACCESS accessAfter,
-        D3D12_BARRIER_LAYOUT layoutBefore,
-        D3D12_BARRIER_LAYOUT layoutAfter,
-        ID3D12Resource *pRes,
-        const D3D12_BARRIER_SUBRESOURCE_RANGE &subresources,
-        D3D12_TEXTURE_BARRIER_FLAGS flag = D3D12_TEXTURE_BARRIER_FLAG_NONE) noexcept : D3D12_TEXTURE_BARRIER {
-            syncBefore,
-            syncAfter,
-            accessBefore,
-            accessAfter,
-            layoutBefore,
-            layoutAfter,
-            pRes,
-            subresources,
-            flag
-        }
-    {}
-};
-
-class CD3DX12_BARRIER_GROUP : public D3D12_BARRIER_GROUP
-{
-public:
-    CD3DX12_BARRIER_GROUP() = default;
-    CD3DX12_BARRIER_GROUP(const D3D12_BARRIER_GROUP &o) noexcept : D3D12_BARRIER_GROUP(o){}
-    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_BUFFER_BARRIER *pBarriers) noexcept
-    {
-        Type = D3D12_BARRIER_TYPE_BUFFER;
-        NumBarriers = numBarriers;
-        pBufferBarriers = pBarriers;
-    }
-    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_TEXTURE_BARRIER *pBarriers) noexcept
-    {
-        Type = D3D12_BARRIER_TYPE_TEXTURE;
-        NumBarriers = numBarriers;
-        pTextureBarriers = pBarriers;
-    }
-    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_GLOBAL_BARRIER *pBarriers) noexcept
-    {
-        Type = D3D12_BARRIER_TYPE_GLOBAL;
-        NumBarriers = numBarriers;
-        pGlobalBarriers = pBarriers;
-    }
-};
-
-
-#ifndef D3DX12_NO_CHECK_FEATURE_SUPPORT_CLASS
-
-//================================================================================================
-// D3DX12 Check Feature Support
-//================================================================================================
-
-#include <vector>
-
-class CD3DX12FeatureSupport
-{
-public: // Function declaration
-    // Default constructor that creates an empty object
-    CD3DX12FeatureSupport() noexcept;
-
-    // Initialize data from the given device
-    HRESULT Init(ID3D12Device* pDevice);
-
-    // Retreives the status of the object. If an error occurred in the initialization process, the function returns the error code.
-    HRESULT GetStatus() const noexcept { return m_hStatus; }
-
-    // Getter functions for each feature class
-    // D3D12_OPTIONS
-    BOOL DoublePrecisionFloatShaderOps() const noexcept;
-    BOOL OutputMergerLogicOp() const noexcept;
-    D3D12_SHADER_MIN_PRECISION_SUPPORT MinPrecisionSupport() const noexcept;
-    D3D12_TILED_RESOURCES_TIER TiledResourcesTier() const noexcept;
-    D3D12_RESOURCE_BINDING_TIER ResourceBindingTier() const noexcept;
-    BOOL PSSpecifiedStencilRefSupported() const noexcept;
-    BOOL TypedUAVLoadAdditionalFormats() const noexcept;
-    BOOL ROVsSupported() const noexcept;
-    D3D12_CONSERVATIVE_RASTERIZATION_TIER ConservativeRasterizationTier() const noexcept;
-    BOOL StandardSwizzle64KBSupported() const noexcept;
-    BOOL CrossAdapterRowMajorTextureSupported() const noexcept;
-    BOOL VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation() const noexcept;
-    D3D12_RESOURCE_HEAP_TIER ResourceHeapTier() const noexcept;
-    D3D12_CROSS_NODE_SHARING_TIER CrossNodeSharingTier() const noexcept;
-    UINT MaxGPUVirtualAddressBitsPerResource() const noexcept;
-
-    // FEATURE_LEVELS
-    D3D_FEATURE_LEVEL MaxSupportedFeatureLevel() const noexcept;
-
-    // FORMAT_SUPPORT
-    HRESULT FormatSupport(DXGI_FORMAT Format, D3D12_FORMAT_SUPPORT1& Support1, D3D12_FORMAT_SUPPORT2& Support2) const;
-
-    // MUTLTISAMPLE_QUALITY_LEVELS
-    HRESULT MultisampleQualityLevels(DXGI_FORMAT Format, UINT SampleCount, D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags, UINT& NumQualityLevels) const;
-
-    // FORMAT_INFO
-    HRESULT FormatInfo(DXGI_FORMAT Format, UINT8& PlaneCount) const;
-
-    // GPU_VIRTUAL_ADDRESS_SUPPORT
-    UINT MaxGPUVirtualAddressBitsPerProcess() const noexcept;
-
-    // SHADER_MODEL
-    D3D_SHADER_MODEL HighestShaderModel() const noexcept;
-
-    // D3D12_OPTIONS1
-    BOOL WaveOps() const noexcept;
-    UINT WaveLaneCountMin() const noexcept;
-    UINT WaveLaneCountMax() const noexcept;
-    UINT TotalLaneCount() const noexcept;
-    BOOL ExpandedComputeResourceStates() const noexcept;
-    BOOL Int64ShaderOps() const noexcept;
-
-    // PROTECTED_RESOURCE_SESSION_SUPPORT
-    D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS ProtectedResourceSessionSupport(UINT NodeIndex = 0) const;
-
-    // ROOT_SIGNATURE
-    D3D_ROOT_SIGNATURE_VERSION HighestRootSignatureVersion() const noexcept;
-
-    // ARCHITECTURE1
-    BOOL TileBasedRenderer(UINT NodeIndex = 0) const;
-    BOOL UMA(UINT NodeIndex = 0) const;
-    BOOL CacheCoherentUMA(UINT NodeIndex = 0) const;
-    BOOL IsolatedMMU(UINT NodeIndex = 0) const;
-
-    // D3D12_OPTIONS2
-    BOOL DepthBoundsTestSupported() const noexcept;
-    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER ProgrammableSamplePositionsTier() const noexcept;
-
-    // SHADER_CACHE
-    D3D12_SHADER_CACHE_SUPPORT_FLAGS ShaderCacheSupportFlags() const noexcept;
-
-    // COMMAND_QUEUE_PRIORITY
-    BOOL CommandQueuePrioritySupported(D3D12_COMMAND_LIST_TYPE CommandListType, UINT Priority);
-
-    // D3D12_OPTIONS3
-    BOOL CopyQueueTimestampQueriesSupported() const noexcept;
-    BOOL CastingFullyTypedFormatSupported() const noexcept;
-    D3D12_COMMAND_LIST_SUPPORT_FLAGS WriteBufferImmediateSupportFlags() const noexcept;
-    D3D12_VIEW_INSTANCING_TIER ViewInstancingTier() const noexcept;
-    BOOL BarycentricsSupported() const noexcept;
-
-    // EXISTING_HEAPS
-    BOOL ExistingHeapsSupported() const noexcept;
-
-    // D3D12_OPTIONS4
-    BOOL MSAA64KBAlignedTextureSupported() const noexcept;
-    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER SharedResourceCompatibilityTier() const noexcept;
-    BOOL Native16BitShaderOpsSupported() const noexcept;
-
-    // SERIALIZATION
-    D3D12_HEAP_SERIALIZATION_TIER HeapSerializationTier(UINT NodeIndex = 0) const;
-
-    // CROSS_NODE
-    // CrossNodeSharingTier handled in D3D12Options
-    BOOL CrossNodeAtomicShaderInstructions() const noexcept;
-
-    // D3D12_OPTIONS5
-    BOOL SRVOnlyTiledResourceTier3() const noexcept;
-    D3D12_RENDER_PASS_TIER RenderPassesTier() const noexcept;
-    D3D12_RAYTRACING_TIER RaytracingTier() const noexcept;
-
-    // DISPLAYABLE
-    BOOL DisplayableTexture() const noexcept;
-    // SharedResourceCompatibilityTier handled in D3D12Options4
-
-    // D3D12_OPTIONS6
-    BOOL AdditionalShadingRatesSupported() const noexcept;
-    BOOL PerPrimitiveShadingRateSupportedWithViewportIndexing() const noexcept;
-    D3D12_VARIABLE_SHADING_RATE_TIER VariableShadingRateTier() const noexcept;
-    UINT ShadingRateImageTileSize() const noexcept;
-    BOOL BackgroundProcessingSupported() const noexcept;
-
-    // QUERY_META_COMMAND
-    HRESULT QueryMetaCommand(D3D12_FEATURE_DATA_QUERY_META_COMMAND& dQueryMetaCommand) const;
-
-    // D3D12_OPTIONS7
-    D3D12_MESH_SHADER_TIER MeshShaderTier() const noexcept;
-    D3D12_SAMPLER_FEEDBACK_TIER SamplerFeedbackTier() const noexcept;
-
-    // PROTECTED_RESOURCE_SESSION_TYPE_COUNT
-    UINT ProtectedResourceSessionTypeCount(UINT NodeIndex = 0) const;
-
-    // PROTECTED_RESOURCE_SESSION_TYPES
-    std::vector<GUID> ProtectedResourceSessionTypes(UINT NodeIndex = 0) const;
-
-    // D3D12_OPTIONS8
-    BOOL UnalignedBlockTexturesSupported() const noexcept;
-
-    // D3D12_OPTIONS9
-    BOOL MeshShaderPipelineStatsSupported() const noexcept;
-    BOOL MeshShaderSupportsFullRangeRenderTargetArrayIndex() const noexcept;
-    BOOL AtomicInt64OnTypedResourceSupported() const noexcept;
-    BOOL AtomicInt64OnGroupSharedSupported() const noexcept;
-    BOOL DerivativesInMeshAndAmplificationShadersSupported() const noexcept;
-    D3D12_WAVE_MMA_TIER WaveMMATier() const noexcept;
-
-    // D3D12_OPTIONS10
-    BOOL VariableRateShadingSumCombinerSupported() const noexcept;
-    BOOL MeshShaderPerPrimitiveShadingRateSupported() const noexcept;
-
-    // D3D12_OPTIONS11
-    BOOL AtomicInt64OnDescriptorHeapResourceSupported() const noexcept;
-
-    // D3D12_OPTIONS12
-    D3D12_TRI_STATE MSPrimitivesPipelineStatisticIncludesCulledPrimitives() const noexcept;
-    BOOL EnhancedBarriersSupported() const noexcept;
-    BOOL RelaxedFormatCastingSupported() const noexcept;
-
-    // D3D12_OPTIONS13
-    BOOL UnrestrictedBufferTextureCopyPitchSupported() const noexcept;
-    BOOL UnrestrictedVertexElementAlignmentSupported() const noexcept;
-    BOOL InvertedViewportHeightFlipsYSupported() const noexcept;
-    BOOL InvertedViewportDepthFlipsZSupported() const noexcept;
-    BOOL TextureCopyBetweenDimensionsSupported() const noexcept;
-    BOOL AlphaBlendFactorSupported() const noexcept;
-
-    // D3D12_OPTIONS14
-    BOOL AdvancedTextureOpsSupported() const noexcept;
-    BOOL WriteableMSAATexturesSupported() const noexcept;
-    BOOL IndependentFrontAndBackStencilRefMaskSupported() const noexcept;
-
-    // D3D12_OPTIONS15
-    BOOL TriangleFanSupported() const noexcept;
-    BOOL DynamicIndexBufferStripCutSupported() const noexcept;
-
-private: // Private structs and helpers declaration
-    struct ProtectedResourceSessionTypesLocal : D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES
-    {
-        std::vector<GUID> TypeVec;
-    };
-
-    // Helper function to decide the highest shader model supported by the system
-    // Stores the result in m_dShaderModel
-    // Must be updated whenever a new shader model is added to the d3d12.h header
-    HRESULT QueryHighestShaderModel();
-
-    // Helper function to decide the highest root signature supported
-    // Must be updated whenever a new root signature version is added to the d3d12.h header
-    HRESULT QueryHighestRootSignatureVersion();
-
-    // Helper funcion to decide the highest feature level
-    HRESULT QueryHighestFeatureLevel();
-
-    // Helper function to initialize local protected resource session types structs
-    HRESULT QueryProtectedResourceSessionTypes(UINT NodeIndex, UINT Count);
-
-private: // Member data
-    // Pointer to the underlying device
-    ID3D12Device* m_pDevice;
-
-    // Stores the error code from initialization
-    HRESULT m_hStatus;
-
-    // Feature support data structs
-    D3D12_FEATURE_DATA_D3D12_OPTIONS m_dOptions;
-    D3D_FEATURE_LEVEL m_eMaxFeatureLevel;
-    D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT m_dGPUVASupport;
-    D3D12_FEATURE_DATA_SHADER_MODEL m_dShaderModel;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS1 m_dOptions1;
-    std::vector<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_SUPPORT> m_dProtectedResourceSessionSupport;
-    D3D12_FEATURE_DATA_ROOT_SIGNATURE m_dRootSignature;
-    std::vector<D3D12_FEATURE_DATA_ARCHITECTURE1> m_dArchitecture1;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS2 m_dOptions2;
-    D3D12_FEATURE_DATA_SHADER_CACHE m_dShaderCache;
-    D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY m_dCommandQueuePriority;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS3 m_dOptions3;
-    D3D12_FEATURE_DATA_EXISTING_HEAPS m_dExistingHeaps;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS4 m_dOptions4;
-    std::vector<D3D12_FEATURE_DATA_SERIALIZATION> m_dSerialization; // Cat2 NodeIndex
-    D3D12_FEATURE_DATA_CROSS_NODE m_dCrossNode;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS5 m_dOptions5;
-    D3D12_FEATURE_DATA_DISPLAYABLE m_dDisplayable;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS6 m_dOptions6;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS7 m_dOptions7;
-    std::vector<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPE_COUNT> m_dProtectedResourceSessionTypeCount; // Cat2 NodeIndex
-    std::vector<ProtectedResourceSessionTypesLocal> m_dProtectedResourceSessionTypes; // Cat3
-    D3D12_FEATURE_DATA_D3D12_OPTIONS8 m_dOptions8;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS9 m_dOptions9;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS10 m_dOptions10;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS11 m_dOptions11;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS12 m_dOptions12;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS13 m_dOptions13;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS14 m_dOptions14;
-    D3D12_FEATURE_DATA_D3D12_OPTIONS15 m_dOptions15;
-};
-
-// Implementations for CD3DX12FeatureSupport functions
-
-// Macro to set up a getter function for each entry in feature support data
-// The getter function will have the same name as the feature option name
-#define FEATURE_SUPPORT_GET(RETTYPE,FEATURE,OPTION) \
-inline RETTYPE CD3DX12FeatureSupport::OPTION() const noexcept \
-{ \
-    return FEATURE.OPTION; \
-}
-
-// Macro to set up a getter function for each entry in feature support data
-// Also specifies the name for the function which can be different from the feature name
-#define FEATURE_SUPPORT_GET_NAME(RETTYPE,FEATURE,OPTION,NAME) \
-inline RETTYPE CD3DX12FeatureSupport::NAME() const noexcept \
-{\
-    return FEATURE.OPTION; \
-}
-
-// Macro to set up a getter function for feature data indexed by the graphics node ID
-// The default parameter is 0, or the first availabe graphics device node
-#define FEATURE_SUPPORT_GET_NODE_INDEXED(RETTYPE,FEATURE,OPTION) \
-inline RETTYPE CD3DX12FeatureSupport::OPTION(UINT NodeIndex) const \
-{\
-    return FEATURE[NodeIndex].OPTION; \
-}
-
-// Macro to set up a getter function for feature data indexed by NodeIndex
-// Allows a custom name for the getter function
-#define FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(RETTYPE,FEATURE,OPTION,NAME) \
-inline RETTYPE CD3DX12FeatureSupport::NAME(UINT NodeIndex) const \
-{\
-    return FEATURE[NodeIndex].OPTION; \
-}
-
-inline CD3DX12FeatureSupport::CD3DX12FeatureSupport() noexcept
-: m_pDevice(nullptr)
-, m_hStatus(E_INVALIDARG)
-, m_dOptions{}
-, m_eMaxFeatureLevel{}
-, m_dGPUVASupport{}
-, m_dShaderModel{}
-, m_dOptions1{}
-, m_dRootSignature{}
-, m_dOptions2{}
-, m_dShaderCache{}
-, m_dCommandQueuePriority{}
-, m_dOptions3{}
-, m_dExistingHeaps{}
-, m_dOptions4{}
-, m_dCrossNode{}
-, m_dOptions5{}
-, m_dDisplayable{}
-, m_dOptions6{}
-, m_dOptions7{}
-, m_dOptions8{}
-, m_dOptions9{}
-, m_dOptions10{}
-, m_dOptions11{}
-, m_dOptions12{}
-, m_dOptions13{}
-, m_dOptions14{}
-, m_dOptions15{}
-{}
-
-inline HRESULT CD3DX12FeatureSupport::Init(ID3D12Device* pDevice)
-{
-    if (!pDevice)
-    {
-        m_hStatus = E_INVALIDARG;
-        return m_hStatus;
-    }
-
-    m_pDevice = pDevice;
-
-    // Initialize static feature support data structures
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_dOptions, sizeof(m_dOptions))))
-    {
-        m_dOptions.DoublePrecisionFloatShaderOps = false;
-        m_dOptions.OutputMergerLogicOp = false;
-        m_dOptions.MinPrecisionSupport = D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE;
-        m_dOptions.TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
-        m_dOptions.ResourceBindingTier = static_cast<D3D12_RESOURCE_BINDING_TIER>(0);
-        m_dOptions.PSSpecifiedStencilRefSupported = false;
-        m_dOptions.TypedUAVLoadAdditionalFormats = false;
-        m_dOptions.ROVsSupported = false;
-        m_dOptions.ConservativeRasterizationTier = D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED;
-        m_dOptions.MaxGPUVirtualAddressBitsPerResource = 0;
-        m_dOptions.StandardSwizzle64KBSupported = false;
-        m_dOptions.CrossNodeSharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED;
-        m_dOptions.CrossAdapterRowMajorTextureSupported = false;
-        m_dOptions.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = false;
-        m_dOptions.ResourceHeapTier = static_cast<D3D12_RESOURCE_HEAP_TIER>(0);
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT, &m_dGPUVASupport, sizeof(m_dGPUVASupport))))
-    {
-        m_dGPUVASupport.MaxGPUVirtualAddressBitsPerProcess = 0;
-        m_dGPUVASupport.MaxGPUVirtualAddressBitsPerResource = 0;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &m_dOptions1, sizeof(m_dOptions1))))
-    {
-        m_dOptions1.WaveOps = false;
-        m_dOptions1.WaveLaneCountMax = 0;
-        m_dOptions1.WaveLaneCountMin = 0;
-        m_dOptions1.TotalLaneCount = 0;
-        m_dOptions1.ExpandedComputeResourceStates = 0;
-        m_dOptions1.Int64ShaderOps = 0;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &m_dOptions2, sizeof(m_dOptions2))))
-    {
-        m_dOptions2.DepthBoundsTestSupported = false;
-        m_dOptions2.ProgrammableSamplePositionsTier = D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_CACHE, &m_dShaderCache, sizeof(m_dShaderCache))))
-    {
-        m_dShaderCache.SupportFlags = D3D12_SHADER_CACHE_SUPPORT_NONE;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &m_dOptions3, sizeof(m_dOptions3))))
-    {
-        m_dOptions3.CopyQueueTimestampQueriesSupported = false;
-        m_dOptions3.CastingFullyTypedFormatSupported = false;
-        m_dOptions3.WriteBufferImmediateSupportFlags = D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE;
-        m_dOptions3.ViewInstancingTier = D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
-        m_dOptions3.BarycentricsSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_EXISTING_HEAPS, &m_dExistingHeaps, sizeof(m_dExistingHeaps))))
-    {
-        m_dExistingHeaps.Supported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &m_dOptions4, sizeof(m_dOptions4))))
-    {
-        m_dOptions4.MSAA64KBAlignedTextureSupported = false;
-        m_dOptions4.Native16BitShaderOpsSupported = false;
-        m_dOptions4.SharedResourceCompatibilityTier = D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_CROSS_NODE, &m_dCrossNode, sizeof(m_dCrossNode))))
-    {
-        m_dCrossNode.SharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED;
-        m_dCrossNode.AtomicShaderInstructions = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &m_dOptions5, sizeof(m_dOptions5))))
-    {
-        m_dOptions5.SRVOnlyTiledResourceTier3 = false;
-        m_dOptions5.RenderPassesTier = D3D12_RENDER_PASS_TIER_0;
-        m_dOptions5.RaytracingTier = D3D12_RAYTRACING_TIER_NOT_SUPPORTED;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_DISPLAYABLE, &m_dDisplayable, sizeof(m_dDisplayable))))
-    {
-        m_dDisplayable.DisplayableTexture = false;
-        m_dDisplayable.SharedResourceCompatibilityTier = D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &m_dOptions6, sizeof(m_dOptions6))))
-    {
-        m_dOptions6.AdditionalShadingRatesSupported = false;
-        m_dOptions6.PerPrimitiveShadingRateSupportedWithViewportIndexing = false;
-        m_dOptions6.VariableShadingRateTier = D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
-        m_dOptions6.ShadingRateImageTileSize = 0;
-        m_dOptions6.BackgroundProcessingSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &m_dOptions7, sizeof(m_dOptions7))))
-    {
-        m_dOptions7.MeshShaderTier = D3D12_MESH_SHADER_TIER_NOT_SUPPORTED;
-        m_dOptions7.SamplerFeedbackTier = D3D12_SAMPLER_FEEDBACK_TIER_NOT_SUPPORTED;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS8, &m_dOptions8, sizeof(m_dOptions8))))
-    {
-        m_dOptions8.UnalignedBlockTexturesSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS9, &m_dOptions9, sizeof(m_dOptions9))))
-    {
-        m_dOptions9.MeshShaderPipelineStatsSupported = false;
-        m_dOptions9.MeshShaderSupportsFullRangeRenderTargetArrayIndex = false;
-        m_dOptions9.AtomicInt64OnGroupSharedSupported = false;
-        m_dOptions9.AtomicInt64OnTypedResourceSupported = false;
-        m_dOptions9.DerivativesInMeshAndAmplificationShadersSupported = false;
-        m_dOptions9.WaveMMATier = D3D12_WAVE_MMA_TIER_NOT_SUPPORTED;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS10, &m_dOptions10, sizeof(m_dOptions10))))
-    {
-        m_dOptions10.MeshShaderPerPrimitiveShadingRateSupported = false;
-        m_dOptions10.VariableRateShadingSumCombinerSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS11, &m_dOptions11, sizeof(m_dOptions11))))
-    {
-        m_dOptions11.AtomicInt64OnDescriptorHeapResourceSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &m_dOptions12, sizeof(m_dOptions12))))
-    {
-        m_dOptions12.MSPrimitivesPipelineStatisticIncludesCulledPrimitives = D3D12_TRI_STATE::D3D12_TRI_STATE_UNKNOWN;
-        m_dOptions12.EnhancedBarriersSupported = false;
-        m_dOptions12.RelaxedFormatCastingSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS13, &m_dOptions13, sizeof(m_dOptions13))))
-    {
-        m_dOptions13.UnrestrictedBufferTextureCopyPitchSupported = false;
-        m_dOptions13.UnrestrictedVertexElementAlignmentSupported = false;
-        m_dOptions13.InvertedViewportHeightFlipsYSupported = false;
-        m_dOptions13.InvertedViewportDepthFlipsZSupported = false;
-        m_dOptions13.TextureCopyBetweenDimensionsSupported = false;
-        m_dOptions13.AlphaBlendFactorSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS14, &m_dOptions14, sizeof(m_dOptions14))))
-    {
-        m_dOptions14.AdvancedTextureOpsSupported = false;
-        m_dOptions14.WriteableMSAATexturesSupported = false;
-        m_dOptions14.IndependentFrontAndBackStencilRefMaskSupported = false;
-    }
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS15, &m_dOptions15, sizeof(m_dOptions15))))
-    {
-        m_dOptions15.TriangleFanSupported = false;
-        m_dOptions15.DynamicIndexBufferStripCutSupported = false;
-    }
-
-    // Initialize per-node feature support data structures
-    const UINT uNodeCount = m_pDevice->GetNodeCount();
-    m_dProtectedResourceSessionSupport.resize(uNodeCount);
-    m_dArchitecture1.resize(uNodeCount);
-    m_dSerialization.resize(uNodeCount);
-    m_dProtectedResourceSessionTypeCount.resize(uNodeCount);
-    m_dProtectedResourceSessionTypes.resize(uNodeCount);
-    for (UINT NodeIndex = 0; NodeIndex < uNodeCount; NodeIndex++)
-    {
-        m_dProtectedResourceSessionSupport[NodeIndex].NodeIndex = NodeIndex;
-        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_SUPPORT, &m_dProtectedResourceSessionSupport[NodeIndex], sizeof(m_dProtectedResourceSessionSupport[NodeIndex]))))
-        {
-            m_dProtectedResourceSessionSupport[NodeIndex].Support = D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAG_NONE;
-        }
-
-        m_dArchitecture1[NodeIndex].NodeIndex = NodeIndex;
-        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE1, &m_dArchitecture1[NodeIndex], sizeof(m_dArchitecture1[NodeIndex]))))
-        {
-            D3D12_FEATURE_DATA_ARCHITECTURE dArchLocal = {};
-            dArchLocal.NodeIndex = NodeIndex;
-            if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &dArchLocal, sizeof(dArchLocal))))
-            {
-                dArchLocal.TileBasedRenderer = false;
-                dArchLocal.UMA = false;
-                dArchLocal.CacheCoherentUMA = false;
-            }
-
-            m_dArchitecture1[NodeIndex].TileBasedRenderer = dArchLocal.TileBasedRenderer;
-            m_dArchitecture1[NodeIndex].UMA = dArchLocal.UMA;
-            m_dArchitecture1[NodeIndex].CacheCoherentUMA = dArchLocal.CacheCoherentUMA;
-            m_dArchitecture1[NodeIndex].IsolatedMMU = false;
-        }
-
-        m_dSerialization[NodeIndex].NodeIndex = NodeIndex;
-        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SERIALIZATION, &m_dSerialization[NodeIndex], sizeof(m_dSerialization[NodeIndex]))))
-        {
-            m_dSerialization[NodeIndex].HeapSerializationTier = D3D12_HEAP_SERIALIZATION_TIER_0;
-        }
-
-        m_dProtectedResourceSessionTypeCount[NodeIndex].NodeIndex = NodeIndex;
-        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPE_COUNT, &m_dProtectedResourceSessionTypeCount[NodeIndex], sizeof(m_dProtectedResourceSessionTypeCount[NodeIndex]))))
-        {
-            m_dProtectedResourceSessionTypeCount[NodeIndex].Count = 0;
-        }
-
-        // Special procedure to initialize local protected resource session types structs
-        // Must wait until session type count initialized
-        QueryProtectedResourceSessionTypes(NodeIndex, m_dProtectedResourceSessionTypeCount[NodeIndex].Count);
-    }
-
-    // Initialize features that requires highest version check
-    if (FAILED(m_hStatus = QueryHighestShaderModel()))
-    {
-        return m_hStatus;
-    }
-
-    if (FAILED(m_hStatus = QueryHighestRootSignatureVersion()))
-    {
-        return m_hStatus;
-    }
-
-    // Initialize Feature Levels data
-    if (FAILED(m_hStatus = QueryHighestFeatureLevel()))
-    {
-        return m_hStatus;
-    }
-
-    return m_hStatus;
-}
-
-// 0: D3D12_OPTIONS
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, DoublePrecisionFloatShaderOps);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, OutputMergerLogicOp);
-FEATURE_SUPPORT_GET(D3D12_SHADER_MIN_PRECISION_SUPPORT, m_dOptions, MinPrecisionSupport);
-FEATURE_SUPPORT_GET(D3D12_TILED_RESOURCES_TIER, m_dOptions, TiledResourcesTier);
-FEATURE_SUPPORT_GET(D3D12_RESOURCE_BINDING_TIER, m_dOptions, ResourceBindingTier);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, PSSpecifiedStencilRefSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, TypedUAVLoadAdditionalFormats);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, ROVsSupported);
-FEATURE_SUPPORT_GET(D3D12_CONSERVATIVE_RASTERIZATION_TIER, m_dOptions, ConservativeRasterizationTier);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, StandardSwizzle64KBSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, CrossAdapterRowMajorTextureSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions, VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation);
-FEATURE_SUPPORT_GET(D3D12_RESOURCE_HEAP_TIER, m_dOptions, ResourceHeapTier);
-
-// Special procedure for handling caps that is also part of other features
-inline D3D12_CROSS_NODE_SHARING_TIER CD3DX12FeatureSupport::CrossNodeSharingTier() const noexcept
-{
-    if (m_dCrossNode.SharingTier > D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED)
-    {
-        return m_dCrossNode.SharingTier;
-    }
-    else
-    {
-        return m_dOptions.CrossNodeSharingTier;
-    }
-}
-
-inline UINT CD3DX12FeatureSupport::MaxGPUVirtualAddressBitsPerResource() const noexcept
-{
-    if (m_dOptions.MaxGPUVirtualAddressBitsPerResource > 0)
-    {
-        return m_dOptions.MaxGPUVirtualAddressBitsPerResource;
-    }
-    else
-    {
-        return m_dGPUVASupport.MaxGPUVirtualAddressBitsPerResource;
-    }
-}
-
-// 1: Architecture
-// Combined with Architecture1
-
-// 2: Feature Levels
-// Simply returns the highest supported feature level
-inline D3D_FEATURE_LEVEL CD3DX12FeatureSupport::MaxSupportedFeatureLevel() const noexcept
-{
-    return m_eMaxFeatureLevel;
-}
-
-// 3: Feature Format Support
-inline HRESULT CD3DX12FeatureSupport::FormatSupport(DXGI_FORMAT Format, D3D12_FORMAT_SUPPORT1& Support1, D3D12_FORMAT_SUPPORT2& Support2) const
-{
-    D3D12_FEATURE_DATA_FORMAT_SUPPORT dFormatSupport;
-    dFormatSupport.Format = Format;
-
-    // It is possible that the function call returns an error
-    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dFormatSupport, sizeof(D3D12_FEATURE_DATA_FORMAT_SUPPORT));
-
-    Support1 = dFormatSupport.Support1;
-    Support2 = dFormatSupport.Support2; // Two outputs. Probably better just to take in the struct as an argument?
-
-    return result;
-}
-
-// 4: Multisample Quality Levels
-inline HRESULT CD3DX12FeatureSupport::MultisampleQualityLevels(DXGI_FORMAT Format, UINT SampleCount, D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags, UINT& NumQualityLevels) const
-{
-    D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS dMultisampleQualityLevels;
-    dMultisampleQualityLevels.Format = Format;
-    dMultisampleQualityLevels.SampleCount = SampleCount;
-    dMultisampleQualityLevels.Flags = Flags;
-
-    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &dMultisampleQualityLevels, sizeof(D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS));
-
-    if (SUCCEEDED(result))
-    {
-        NumQualityLevels = dMultisampleQualityLevels.NumQualityLevels;
-    }
-    else
-    {
-        NumQualityLevels = 0;
-    }
-
-    return result;
-}
-
-// 5: Format Info
-inline HRESULT CD3DX12FeatureSupport::FormatInfo(DXGI_FORMAT Format, UINT8& PlaneCount) const
-{
-    D3D12_FEATURE_DATA_FORMAT_INFO dFormatInfo;
-    dFormatInfo.Format = Format;
-
-    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &dFormatInfo, sizeof(D3D12_FEATURE_DATA_FORMAT_INFO));
-    if (FAILED(result))
-    {
-        PlaneCount = 0;
-    }
-    else
-    {
-        PlaneCount = dFormatInfo.PlaneCount;
-    }
-    return result;
-}
-
-// 6: GPU Virtual Address Support
-// MaxGPUVirtualAddressBitsPerResource handled in D3D12Options
-FEATURE_SUPPORT_GET(UINT, m_dGPUVASupport, MaxGPUVirtualAddressBitsPerProcess);
-
-// 7: Shader Model
-inline D3D_SHADER_MODEL CD3DX12FeatureSupport::HighestShaderModel() const noexcept
-{
-    return m_dShaderModel.HighestShaderModel;
-}
-
-// 8: D3D12 Options1
-FEATURE_SUPPORT_GET(BOOL, m_dOptions1, WaveOps);
-FEATURE_SUPPORT_GET(UINT, m_dOptions1, WaveLaneCountMin);
-FEATURE_SUPPORT_GET(UINT, m_dOptions1, WaveLaneCountMax);
-FEATURE_SUPPORT_GET(UINT, m_dOptions1, TotalLaneCount);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions1, ExpandedComputeResourceStates);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions1, Int64ShaderOps);
-
-// 10: Protected Resource Session Support
-inline D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS CD3DX12FeatureSupport::ProtectedResourceSessionSupport(UINT NodeIndex) const
-{
-    return m_dProtectedResourceSessionSupport[NodeIndex].Support;
-}
-
-// 12: Root Signature
-inline D3D_ROOT_SIGNATURE_VERSION CD3DX12FeatureSupport::HighestRootSignatureVersion() const noexcept
-{
-    return m_dRootSignature.HighestVersion;
-}
-
-// 16: Architecture1
-// Same data fields can be queried from m_dArchitecture
-FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, TileBasedRenderer);
-FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, UMA);
-FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, CacheCoherentUMA);
-FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, IsolatedMMU);
-
-// 18: D3D12 Options2
-FEATURE_SUPPORT_GET(BOOL, m_dOptions2, DepthBoundsTestSupported);
-FEATURE_SUPPORT_GET(D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER, m_dOptions2, ProgrammableSamplePositionsTier);
-
-// 19: Shader Cache
-FEATURE_SUPPORT_GET_NAME(D3D12_SHADER_CACHE_SUPPORT_FLAGS, m_dShaderCache, SupportFlags, ShaderCacheSupportFlags);
-
-// 20: Command Queue Priority
-inline BOOL CD3DX12FeatureSupport::CommandQueuePrioritySupported(D3D12_COMMAND_LIST_TYPE CommandListType, UINT Priority)
-{
-    m_dCommandQueuePriority.CommandListType = CommandListType;
-    m_dCommandQueuePriority.Priority = Priority;
-
-    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_COMMAND_QUEUE_PRIORITY, &m_dCommandQueuePriority, sizeof(D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY))))
-    {
-        return false;
-    }
-
-    return m_dCommandQueuePriority.PriorityForTypeIsSupported;
-}
-
-// 21: D3D12 Options3
-FEATURE_SUPPORT_GET(BOOL, m_dOptions3, CopyQueueTimestampQueriesSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions3, CastingFullyTypedFormatSupported);
-FEATURE_SUPPORT_GET(D3D12_COMMAND_LIST_SUPPORT_FLAGS, m_dOptions3, WriteBufferImmediateSupportFlags);
-FEATURE_SUPPORT_GET(D3D12_VIEW_INSTANCING_TIER, m_dOptions3, ViewInstancingTier);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions3, BarycentricsSupported);
-
-// 22: Existing Heaps
-FEATURE_SUPPORT_GET_NAME(BOOL, m_dExistingHeaps, Supported, ExistingHeapsSupported);
-
-// 23: D3D12 Options4
-FEATURE_SUPPORT_GET(BOOL, m_dOptions4, MSAA64KBAlignedTextureSupported);
-FEATURE_SUPPORT_GET(D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER, m_dOptions4, SharedResourceCompatibilityTier);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions4, Native16BitShaderOpsSupported);
-
-// 24: Serialization
-FEATURE_SUPPORT_GET_NODE_INDEXED(D3D12_HEAP_SERIALIZATION_TIER, m_dSerialization, HeapSerializationTier);
-
-// 25: Cross Node
-// CrossNodeSharingTier handled in D3D12Options
-FEATURE_SUPPORT_GET_NAME(BOOL, m_dCrossNode, AtomicShaderInstructions, CrossNodeAtomicShaderInstructions);
-
-// 27: D3D12 Options5
-FEATURE_SUPPORT_GET(BOOL, m_dOptions5, SRVOnlyTiledResourceTier3);
-FEATURE_SUPPORT_GET(D3D12_RENDER_PASS_TIER, m_dOptions5, RenderPassesTier);
-FEATURE_SUPPORT_GET(D3D12_RAYTRACING_TIER, m_dOptions5, RaytracingTier);
-
-// 28: Displayable
-FEATURE_SUPPORT_GET(BOOL, m_dDisplayable, DisplayableTexture);
-// SharedResourceCompatibilityTier handled in D3D12Options4
-
-// 30: D3D12 Options6
-FEATURE_SUPPORT_GET(BOOL, m_dOptions6, AdditionalShadingRatesSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions6, PerPrimitiveShadingRateSupportedWithViewportIndexing);
-FEATURE_SUPPORT_GET(D3D12_VARIABLE_SHADING_RATE_TIER, m_dOptions6, VariableShadingRateTier);
-FEATURE_SUPPORT_GET(UINT, m_dOptions6, ShadingRateImageTileSize);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions6, BackgroundProcessingSupported);
-
-// 31: Query Meta Command
-// Keep the original call routine
-inline HRESULT CD3DX12FeatureSupport::QueryMetaCommand(D3D12_FEATURE_DATA_QUERY_META_COMMAND& dQueryMetaCommand) const
-{
-    return m_pDevice->CheckFeatureSupport(D3D12_FEATURE_QUERY_META_COMMAND, &dQueryMetaCommand, sizeof(D3D12_FEATURE_DATA_QUERY_META_COMMAND));
-}
-
-// 32: D3D12 Options7
-FEATURE_SUPPORT_GET(D3D12_MESH_SHADER_TIER, m_dOptions7, MeshShaderTier);
-FEATURE_SUPPORT_GET(D3D12_SAMPLER_FEEDBACK_TIER, m_dOptions7, SamplerFeedbackTier);
-
-// 33: Protected Resource Session Type Count
-FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(UINT, m_dProtectedResourceSessionTypeCount, Count, ProtectedResourceSessionTypeCount);
-
-// 34: Protected Resource Session Types
-FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(std::vector<GUID>, m_dProtectedResourceSessionTypes, TypeVec, ProtectedResourceSessionTypes);
-
-// 36: Options8
-FEATURE_SUPPORT_GET(BOOL, m_dOptions8, UnalignedBlockTexturesSupported);
-
-// 37: Options9
-FEATURE_SUPPORT_GET(BOOL, m_dOptions9, MeshShaderPipelineStatsSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions9, MeshShaderSupportsFullRangeRenderTargetArrayIndex);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions9, AtomicInt64OnTypedResourceSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions9, AtomicInt64OnGroupSharedSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions9, DerivativesInMeshAndAmplificationShadersSupported);
-FEATURE_SUPPORT_GET(D3D12_WAVE_MMA_TIER, m_dOptions9, WaveMMATier);
-
-// 39: Options10
-FEATURE_SUPPORT_GET(BOOL, m_dOptions10, VariableRateShadingSumCombinerSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions10, MeshShaderPerPrimitiveShadingRateSupported);
-
-// 40: Options11
-FEATURE_SUPPORT_GET(BOOL, m_dOptions11, AtomicInt64OnDescriptorHeapResourceSupported);
-
-// 41: Options12
-FEATURE_SUPPORT_GET(D3D12_TRI_STATE, m_dOptions12, MSPrimitivesPipelineStatisticIncludesCulledPrimitives);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions12, EnhancedBarriersSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions12, RelaxedFormatCastingSupported);
-
-// 42: Options13
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, UnrestrictedBufferTextureCopyPitchSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, UnrestrictedVertexElementAlignmentSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, InvertedViewportHeightFlipsYSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, InvertedViewportDepthFlipsZSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, TextureCopyBetweenDimensionsSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions13, AlphaBlendFactorSupported);
-
-// 43: Options14
-FEATURE_SUPPORT_GET(BOOL, m_dOptions14, AdvancedTextureOpsSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions14, WriteableMSAATexturesSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions14, IndependentFrontAndBackStencilRefMaskSupported);
-
-// 44: Options15
-FEATURE_SUPPORT_GET(BOOL, m_dOptions15, TriangleFanSupported);
-FEATURE_SUPPORT_GET(BOOL, m_dOptions15, DynamicIndexBufferStripCutSupported);
-
-// Helper function to decide the highest shader model supported by the system
-// Stores the result in m_dShaderModel
-// Must be updated whenever a new shader model is added to the d3d12.h header
-inline HRESULT CD3DX12FeatureSupport::QueryHighestShaderModel()
-{
-    // Check support in descending order
-    HRESULT result;
-
-    const D3D_SHADER_MODEL allModelVersions[] =
-    {
-        D3D_SHADER_MODEL_6_8,
-        D3D_SHADER_MODEL_6_7,
-        D3D_SHADER_MODEL_6_6,
-        D3D_SHADER_MODEL_6_5,
-        D3D_SHADER_MODEL_6_4,
-        D3D_SHADER_MODEL_6_3,
-        D3D_SHADER_MODEL_6_2,
-        D3D_SHADER_MODEL_6_1,
-        D3D_SHADER_MODEL_6_0,
-        D3D_SHADER_MODEL_5_1
-    };
-    constexpr size_t numModelVersions = sizeof(allModelVersions) / sizeof(D3D_SHADER_MODEL);
-
-    for (size_t i = 0; i < numModelVersions; i++)
-    {
-        m_dShaderModel.HighestShaderModel = allModelVersions[i];
-        result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &m_dShaderModel, sizeof(D3D12_FEATURE_DATA_SHADER_MODEL));
-        if (result != E_INVALIDARG)
-        {
-            // Indicates that the version is recognizable by the runtime and stored in the struct
-            // Also terminate on unexpected error code
-            if (FAILED(result))
-            {
-                m_dShaderModel.HighestShaderModel = static_cast<D3D_SHADER_MODEL>(0);
-            }
-            return result;
-        }
-    }
-
-    // Shader model may not be supported. Continue the rest initializations
-    m_dShaderModel.HighestShaderModel = static_cast<D3D_SHADER_MODEL>(0);
-    return S_OK;
-}
-
-// Helper function to decide the highest root signature supported
-// Must be updated whenever a new root signature version is added to the d3d12.h header
-inline HRESULT CD3DX12FeatureSupport::QueryHighestRootSignatureVersion()
-{
-    HRESULT result;
-
-    const D3D_ROOT_SIGNATURE_VERSION allRootSignatureVersions[] =
-    {
-        D3D_ROOT_SIGNATURE_VERSION_1_1,
-        D3D_ROOT_SIGNATURE_VERSION_1_0,
-        D3D_ROOT_SIGNATURE_VERSION_1,
-    };
-    constexpr size_t numRootSignatureVersions = sizeof(allRootSignatureVersions) / sizeof(D3D_ROOT_SIGNATURE_VERSION);
-
-    for (size_t i = 0; i < numRootSignatureVersions; i++)
-    {
-        m_dRootSignature.HighestVersion = allRootSignatureVersions[i];
-        result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &m_dRootSignature, sizeof(D3D12_FEATURE_DATA_ROOT_SIGNATURE));
-        if (result != E_INVALIDARG)
-        {
-            if (FAILED(result))
-            {
-                m_dRootSignature.HighestVersion = static_cast<D3D_ROOT_SIGNATURE_VERSION>(0);
-            }
-            // If succeeded, the highest version is already written into the member struct
-            return result;
-        }
-    }
-
-    // No version left. Set to invalid value and continue.
-    m_dRootSignature.HighestVersion = static_cast<D3D_ROOT_SIGNATURE_VERSION>(0);
-    return S_OK;
-}
-
-// Helper funcion to decide the highest feature level
-inline HRESULT CD3DX12FeatureSupport::QueryHighestFeatureLevel()
-{
-    HRESULT result;
-
-    // Check against a list of all feature levels present in d3dcommon.h
-    // Needs to be updated for future feature levels
-    const D3D_FEATURE_LEVEL allLevels[] =
-    {
-        D3D_FEATURE_LEVEL_12_2,
-        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,
-        D3D_FEATURE_LEVEL_1_0_CORE
-    };
-
-    D3D12_FEATURE_DATA_FEATURE_LEVELS dFeatureLevel;
-    dFeatureLevel.NumFeatureLevels = static_cast<UINT>(sizeof(allLevels) / sizeof(D3D_FEATURE_LEVEL));
-    dFeatureLevel.pFeatureLevelsRequested = allLevels;
-
-    result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &dFeatureLevel, sizeof(D3D12_FEATURE_DATA_FEATURE_LEVELS));
-    if (SUCCEEDED(result))
-    {
-        m_eMaxFeatureLevel = dFeatureLevel.MaxSupportedFeatureLevel;
-    }
-    else
-    {
-        m_eMaxFeatureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
-
-        if (result == DXGI_ERROR_UNSUPPORTED)
-        {
-            // Indicates that none supported. Continue initialization
-            result = S_OK;
-        }
-    }
-    return result;
-}
-
-// Helper function to initialize local protected resource session types structs
-inline HRESULT CD3DX12FeatureSupport::QueryProtectedResourceSessionTypes(UINT NodeIndex, UINT Count)
-{
-    auto& CurrentPRSTypes = m_dProtectedResourceSessionTypes[NodeIndex];
-    CurrentPRSTypes.NodeIndex = NodeIndex;
-    CurrentPRSTypes.Count = Count;
-    CurrentPRSTypes.TypeVec.resize(CurrentPRSTypes.Count);
-    CurrentPRSTypes.pTypes = CurrentPRSTypes.TypeVec.data();
-
-    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPES, &m_dProtectedResourceSessionTypes[NodeIndex], sizeof(D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES));
-    if (FAILED(result))
-    {
-        // Resize TypeVec to empty
-        CurrentPRSTypes.TypeVec.clear();
-    }
-
-    return result;
-}
-
-#undef FEATURE_SUPPORT_GET
-#undef FEATURE_SUPPORT_GET_NAME
-#undef FEATURE_SUPPORT_GET_NODE_INDEXED
-#undef FEATURE_SUPPORT_GET_NODE_INDEXED_NAME
-
-// end CD3DX12FeatureSupport
-
-#endif // !D3DX12_NO_CHECK_FEATURE_SUPPORT_CLASS
-
-#undef D3DX12_COM_PTR
-#undef D3DX12_COM_PTR_GET
-#undef D3DX12_COM_PTR_ADDRESSOF
-
-#endif // defined( __cplusplus )
-
-#endif //__D3DX12_H__
-

+ 2627 - 0
thirdparty/directx_headers/include/directx/D3D12TokenizedProgramFormat.hpp

@@ -0,0 +1,2627 @@
+#pragma once
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+//
+// High Level Goals
+//
+// - Serve as the runtime/DDI representation for all D3D11 tokenized code,
+//   for all classes of programs, including pixel program, vertex program,
+//   geometry program, etc.
+//
+// - Any information that HLSL needs to give to drivers is encoded in
+//   this token format in some form.
+//
+// - Enable common tools and source code for managing all tokenizable
+//   program formats.
+//
+// - Support extensible token definitions, allowing full customizations for
+//   specific program classes, while maintaining general conventions for all
+//   program models.
+//
+// - Binary backwards compatible with D3D10.  Any token name that was originally
+//   defined with "D3D10" in it is unchanged; D3D11 only adds new tokens.
+//
+// ----------------------------------------------------------------------------
+//
+// Low Level Feature Summary
+//
+// - DWORD based tokens always, for simplicity
+// - Opcode token is generally a single DWORD, though there is a bit indicating
+//   if extended information (extra DWORD(s)) are present
+// - Operand tokens are a completely self contained, extensible format,
+//   with scalar and 4-vector data types as first class citizens, but
+//   allowance for extension to n-component vectors.
+// - Initial operand token identifies register type, register file
+//   structure/dimensionality and mode of indexing for each dimension,
+//   and choice of component selection mechanism (i.e. mask vs. swizzle etc).
+// - Optional additional extended operand tokens can defined things like
+//   modifiers (which are not needed by default).
+// - Operand's immediate index value(s), if needed, appear as subsequent DWORD
+//   values, and if relative addressing is specified, an additional completely
+//   self contained operand definition appears nested in the token sequence.
+//
+// ----------------------------------------------------------------------------
+
+#include <winapifamily.h>
+
+#pragma region Application Family
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_GAMES)
+
+// ----------------------------------------------------------------------------
+// Version Token (VerTok)
+//
+// [07:00] minor version number (0-255)
+// [15:08] major version number (0-255)
+// [31:16] D3D10_SB_TOKENIZED_PROGRAM_TYPE
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_TOKENIZED_PROGRAM_TYPE
+{
+    D3D10_SB_PIXEL_SHADER       = 0,
+    D3D10_SB_VERTEX_SHADER      = 1,
+    D3D10_SB_GEOMETRY_SHADER    = 2,
+    
+    // D3D11 Shaders
+    D3D11_SB_HULL_SHADER        = 3,
+    D3D11_SB_DOMAIN_SHADER      = 4,
+    D3D11_SB_COMPUTE_SHADER     = 5,
+
+    // Subset of D3D12 Shaders where this field is referenced by runtime
+    // Entries from 6-12 are unique to state objects 
+    // (e.g. library, callable and raytracing shaders)
+    D3D12_SB_MESH_SHADER        = 13,
+    D3D12_SB_AMPLIFICATION_SHADER = 14,
+
+    D3D11_SB_RESERVED0          = 0xFFF0
+} D3D10_SB_TOKENIZED_PROGRAM_TYPE;
+
+#define D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK  0xffff0000
+#define D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT 16
+
+// DECODER MACRO: Retrieve program type from version token
+#define DECODE_D3D10_SB_TOKENIZED_PROGRAM_TYPE(VerTok) ((D3D10_SB_TOKENIZED_PROGRAM_TYPE)(((VerTok)&D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK)>>D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT))
+
+#define D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK  0x000000f0
+#define D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT 4
+#define D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK  0x0000000f
+
+// DECODER MACRO: Retrieve major version # from version token
+#define DECODE_D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION(VerTok) (((VerTok)&D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK)>>D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT)
+// DECODER MACRO: Retrieve minor version # from version token
+#define DECODE_D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION(VerTok) ((VerTok)&D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK)
+
+// ENCODER MACRO: Create complete VerTok
+#define ENCODE_D3D10_SB_TOKENIZED_PROGRAM_VERSION_TOKEN(ProgType,MajorVer,MinorVer) ((((ProgType)<<D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT)&D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK)|\
+                                                                               ((((MajorVer)<<D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT)&D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK))|\
+                                                                               ((MinorVer)&D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK))
+
+// ----------------------------------------------------------------------------
+// Length Token (LenTok)
+//
+// Always follows VerTok
+//
+// [31:00] Unsigned integer count of number of
+//              DWORDs in program code, including version
+//              and length tokens.  So the minimum value
+//              is 0x00000002 (if an empty program is ever
+//              valid).
+//
+// ----------------------------------------------------------------------------
+
+// DECODER MACRO: Retrieve program length
+#define DECODE_D3D10_SB_TOKENIZED_PROGRAM_LENGTH(LenTok) (LenTok)
+// ENCODER MACRO: Create complete LenTok
+#define ENCODE_D3D10_SB_TOKENIZED_PROGRAM_LENGTH(Length) (Length)
+#define MAX_D3D10_SB_TOKENIZED_PROGRAM_LENGTH (0xffffffff)
+
+// ----------------------------------------------------------------------------
+// Opcode Format (OpcodeToken0)
+//
+// [10:00] D3D10_SB_OPCODE_TYPE
+// if( [10:00] == D3D10_SB_OPCODE_CUSTOMDATA )
+// {
+//    Token starts a custom-data block.  See "Custom-Data Block Format".
+// }
+// else // standard opcode token
+// {
+//    [23:11] Opcode-Specific Controls
+//    [30:24] Instruction length in DWORDs including the opcode token.
+//    [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//            contains extended opcode token.
+// }
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_OPCODE_TYPE {
+    D3D10_SB_OPCODE_ADD          ,
+    D3D10_SB_OPCODE_AND          ,
+    D3D10_SB_OPCODE_BREAK        ,
+    D3D10_SB_OPCODE_BREAKC       ,
+    D3D10_SB_OPCODE_CALL         ,
+    D3D10_SB_OPCODE_CALLC        ,
+    D3D10_SB_OPCODE_CASE         ,
+    D3D10_SB_OPCODE_CONTINUE     ,
+    D3D10_SB_OPCODE_CONTINUEC    ,
+    D3D10_SB_OPCODE_CUT          ,
+    D3D10_SB_OPCODE_DEFAULT      ,
+    D3D10_SB_OPCODE_DERIV_RTX    ,
+    D3D10_SB_OPCODE_DERIV_RTY    ,
+    D3D10_SB_OPCODE_DISCARD      ,
+    D3D10_SB_OPCODE_DIV          ,
+    D3D10_SB_OPCODE_DP2          ,
+    D3D10_SB_OPCODE_DP3          ,
+    D3D10_SB_OPCODE_DP4          ,
+    D3D10_SB_OPCODE_ELSE         ,
+    D3D10_SB_OPCODE_EMIT         ,
+    D3D10_SB_OPCODE_EMITTHENCUT  ,
+    D3D10_SB_OPCODE_ENDIF        ,
+    D3D10_SB_OPCODE_ENDLOOP      ,
+    D3D10_SB_OPCODE_ENDSWITCH    ,
+    D3D10_SB_OPCODE_EQ           ,
+    D3D10_SB_OPCODE_EXP          ,
+    D3D10_SB_OPCODE_FRC          ,
+    D3D10_SB_OPCODE_FTOI         ,
+    D3D10_SB_OPCODE_FTOU         ,
+    D3D10_SB_OPCODE_GE           ,
+    D3D10_SB_OPCODE_IADD         ,
+    D3D10_SB_OPCODE_IF           ,
+    D3D10_SB_OPCODE_IEQ          ,
+    D3D10_SB_OPCODE_IGE          ,
+    D3D10_SB_OPCODE_ILT          ,
+    D3D10_SB_OPCODE_IMAD         ,
+    D3D10_SB_OPCODE_IMAX         ,
+    D3D10_SB_OPCODE_IMIN         ,
+    D3D10_SB_OPCODE_IMUL         ,
+    D3D10_SB_OPCODE_INE          ,
+    D3D10_SB_OPCODE_INEG         ,
+    D3D10_SB_OPCODE_ISHL         ,
+    D3D10_SB_OPCODE_ISHR         ,
+    D3D10_SB_OPCODE_ITOF         ,
+    D3D10_SB_OPCODE_LABEL        ,
+    D3D10_SB_OPCODE_LD           ,
+    D3D10_SB_OPCODE_LD_MS        ,
+    D3D10_SB_OPCODE_LOG          ,
+    D3D10_SB_OPCODE_LOOP         ,
+    D3D10_SB_OPCODE_LT           ,
+    D3D10_SB_OPCODE_MAD          ,
+    D3D10_SB_OPCODE_MIN          ,
+    D3D10_SB_OPCODE_MAX          ,
+    D3D10_SB_OPCODE_CUSTOMDATA   ,
+    D3D10_SB_OPCODE_MOV          ,
+    D3D10_SB_OPCODE_MOVC         ,
+    D3D10_SB_OPCODE_MUL          ,
+    D3D10_SB_OPCODE_NE           ,
+    D3D10_SB_OPCODE_NOP          ,
+    D3D10_SB_OPCODE_NOT          ,
+    D3D10_SB_OPCODE_OR           ,
+    D3D10_SB_OPCODE_RESINFO      ,
+    D3D10_SB_OPCODE_RET          ,
+    D3D10_SB_OPCODE_RETC         ,
+    D3D10_SB_OPCODE_ROUND_NE     ,
+    D3D10_SB_OPCODE_ROUND_NI     ,
+    D3D10_SB_OPCODE_ROUND_PI     ,
+    D3D10_SB_OPCODE_ROUND_Z      ,
+    D3D10_SB_OPCODE_RSQ          ,
+    D3D10_SB_OPCODE_SAMPLE       ,
+    D3D10_SB_OPCODE_SAMPLE_C     ,
+    D3D10_SB_OPCODE_SAMPLE_C_LZ  ,
+    D3D10_SB_OPCODE_SAMPLE_L     ,
+    D3D10_SB_OPCODE_SAMPLE_D     ,
+    D3D10_SB_OPCODE_SAMPLE_B     ,
+    D3D10_SB_OPCODE_SQRT         ,
+    D3D10_SB_OPCODE_SWITCH       ,
+    D3D10_SB_OPCODE_SINCOS       ,
+    D3D10_SB_OPCODE_UDIV         ,
+    D3D10_SB_OPCODE_ULT          ,
+    D3D10_SB_OPCODE_UGE          ,
+    D3D10_SB_OPCODE_UMUL         ,
+    D3D10_SB_OPCODE_UMAD         ,
+    D3D10_SB_OPCODE_UMAX         ,
+    D3D10_SB_OPCODE_UMIN         ,
+    D3D10_SB_OPCODE_USHR         ,
+    D3D10_SB_OPCODE_UTOF         ,
+    D3D10_SB_OPCODE_XOR          ,
+    D3D10_SB_OPCODE_DCL_RESOURCE                     , // DCL* opcodes have
+    D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER              , // custom operand formats.
+    D3D10_SB_OPCODE_DCL_SAMPLER                      ,
+    D3D10_SB_OPCODE_DCL_INDEX_RANGE                  ,
+    D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY ,
+    D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE           ,
+    D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT      ,
+    D3D10_SB_OPCODE_DCL_INPUT                        ,
+    D3D10_SB_OPCODE_DCL_INPUT_SGV                    ,
+    D3D10_SB_OPCODE_DCL_INPUT_SIV                    ,
+    D3D10_SB_OPCODE_DCL_INPUT_PS                     ,
+    D3D10_SB_OPCODE_DCL_INPUT_PS_SGV                 ,
+    D3D10_SB_OPCODE_DCL_INPUT_PS_SIV                 ,
+    D3D10_SB_OPCODE_DCL_OUTPUT                       ,
+    D3D10_SB_OPCODE_DCL_OUTPUT_SGV                   ,
+    D3D10_SB_OPCODE_DCL_OUTPUT_SIV                   ,
+    D3D10_SB_OPCODE_DCL_TEMPS                        ,
+    D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP               ,
+    D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS                 ,
+
+// -----------------------------------------------
+
+    // This marks the end of D3D10.0 opcodes
+    D3D10_SB_OPCODE_RESERVED0,
+    
+// ---------- DX 10.1 op codes---------------------
+
+    D3D10_1_SB_OPCODE_LOD,
+    D3D10_1_SB_OPCODE_GATHER4,
+    D3D10_1_SB_OPCODE_SAMPLE_POS,
+    D3D10_1_SB_OPCODE_SAMPLE_INFO,
+
+// -----------------------------------------------
+
+    // This marks the end of D3D10.1 opcodes
+    D3D10_1_SB_OPCODE_RESERVED1,
+
+// ---------- DX 11 op codes---------------------
+    D3D11_SB_OPCODE_HS_DECLS                         , // token marks beginning of HS sub-shader
+    D3D11_SB_OPCODE_HS_CONTROL_POINT_PHASE           , // token marks beginning of HS sub-shader
+    D3D11_SB_OPCODE_HS_FORK_PHASE                    , // token marks beginning of HS sub-shader
+    D3D11_SB_OPCODE_HS_JOIN_PHASE                    , // token marks beginning of HS sub-shader
+
+    D3D11_SB_OPCODE_EMIT_STREAM                      ,
+    D3D11_SB_OPCODE_CUT_STREAM                       ,
+    D3D11_SB_OPCODE_EMITTHENCUT_STREAM               ,
+    D3D11_SB_OPCODE_INTERFACE_CALL                   ,
+
+    D3D11_SB_OPCODE_BUFINFO                          ,
+    D3D11_SB_OPCODE_DERIV_RTX_COARSE                 ,
+    D3D11_SB_OPCODE_DERIV_RTX_FINE                   ,
+    D3D11_SB_OPCODE_DERIV_RTY_COARSE                 ,
+    D3D11_SB_OPCODE_DERIV_RTY_FINE                   ,
+    D3D11_SB_OPCODE_GATHER4_C                        ,
+    D3D11_SB_OPCODE_GATHER4_PO                       ,
+    D3D11_SB_OPCODE_GATHER4_PO_C                     ,
+    D3D11_SB_OPCODE_RCP                              ,
+    D3D11_SB_OPCODE_F32TOF16                         ,
+    D3D11_SB_OPCODE_F16TOF32                         ,
+    D3D11_SB_OPCODE_UADDC                            ,
+    D3D11_SB_OPCODE_USUBB                            ,
+    D3D11_SB_OPCODE_COUNTBITS                        ,
+    D3D11_SB_OPCODE_FIRSTBIT_HI                      ,
+    D3D11_SB_OPCODE_FIRSTBIT_LO                      ,
+    D3D11_SB_OPCODE_FIRSTBIT_SHI                     ,
+    D3D11_SB_OPCODE_UBFE                             ,
+    D3D11_SB_OPCODE_IBFE                             ,
+    D3D11_SB_OPCODE_BFI                              ,
+    D3D11_SB_OPCODE_BFREV                            ,
+    D3D11_SB_OPCODE_SWAPC                            ,
+
+    D3D11_SB_OPCODE_DCL_STREAM                       ,
+    D3D11_SB_OPCODE_DCL_FUNCTION_BODY                ,
+    D3D11_SB_OPCODE_DCL_FUNCTION_TABLE               ,
+    D3D11_SB_OPCODE_DCL_INTERFACE                    ,
+    
+    D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT    ,
+    D3D11_SB_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT   ,
+    D3D11_SB_OPCODE_DCL_TESS_DOMAIN                  ,
+    D3D11_SB_OPCODE_DCL_TESS_PARTITIONING            ,
+    D3D11_SB_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE        ,
+    D3D11_SB_OPCODE_DCL_HS_MAX_TESSFACTOR            ,
+    D3D11_SB_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT ,
+    D3D11_SB_OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT ,
+
+    D3D11_SB_OPCODE_DCL_THREAD_GROUP                 ,
+    D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED  ,
+    D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW    ,
+    D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED,
+    D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW,
+    D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED,
+    D3D11_SB_OPCODE_DCL_RESOURCE_RAW                 ,
+    D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED          ,
+    D3D11_SB_OPCODE_LD_UAV_TYPED                     ,
+    D3D11_SB_OPCODE_STORE_UAV_TYPED                  ,
+    D3D11_SB_OPCODE_LD_RAW                           ,
+    D3D11_SB_OPCODE_STORE_RAW                        ,
+    D3D11_SB_OPCODE_LD_STRUCTURED                    ,
+    D3D11_SB_OPCODE_STORE_STRUCTURED                 ,
+    D3D11_SB_OPCODE_ATOMIC_AND                       ,
+    D3D11_SB_OPCODE_ATOMIC_OR                        ,
+    D3D11_SB_OPCODE_ATOMIC_XOR                       ,
+    D3D11_SB_OPCODE_ATOMIC_CMP_STORE                 ,
+    D3D11_SB_OPCODE_ATOMIC_IADD                      ,
+    D3D11_SB_OPCODE_ATOMIC_IMAX                      ,
+    D3D11_SB_OPCODE_ATOMIC_IMIN                      ,
+    D3D11_SB_OPCODE_ATOMIC_UMAX                      ,
+    D3D11_SB_OPCODE_ATOMIC_UMIN                      ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_ALLOC                 ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_CONSUME               ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_IADD                  ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_AND                   ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_OR                    ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_XOR                   ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_EXCH                  ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_CMP_EXCH              ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_IMAX                  ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_IMIN                  ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_UMAX                  ,
+    D3D11_SB_OPCODE_IMM_ATOMIC_UMIN                  ,   
+    D3D11_SB_OPCODE_SYNC                             ,
+    
+    D3D11_SB_OPCODE_DADD                             ,
+    D3D11_SB_OPCODE_DMAX                             ,
+    D3D11_SB_OPCODE_DMIN                             ,
+    D3D11_SB_OPCODE_DMUL                             ,
+    D3D11_SB_OPCODE_DEQ                              ,
+    D3D11_SB_OPCODE_DGE                              ,
+    D3D11_SB_OPCODE_DLT                              ,
+    D3D11_SB_OPCODE_DNE                              ,
+    D3D11_SB_OPCODE_DMOV                             ,
+    D3D11_SB_OPCODE_DMOVC                            ,
+    D3D11_SB_OPCODE_DTOF                             ,
+    D3D11_SB_OPCODE_FTOD                             ,
+
+    D3D11_SB_OPCODE_EVAL_SNAPPED                     ,
+    D3D11_SB_OPCODE_EVAL_SAMPLE_INDEX                ,
+    D3D11_SB_OPCODE_EVAL_CENTROID                    ,
+    
+    D3D11_SB_OPCODE_DCL_GS_INSTANCE_COUNT            ,
+
+    D3D11_SB_OPCODE_ABORT                            ,
+    D3D11_SB_OPCODE_DEBUG_BREAK                      ,
+
+// -----------------------------------------------
+
+    // This marks the end of D3D11.0 opcodes
+    D3D11_SB_OPCODE_RESERVED0,
+
+    D3D11_1_SB_OPCODE_DDIV,
+    D3D11_1_SB_OPCODE_DFMA,
+    D3D11_1_SB_OPCODE_DRCP,
+
+    D3D11_1_SB_OPCODE_MSAD,
+
+    D3D11_1_SB_OPCODE_DTOI,
+    D3D11_1_SB_OPCODE_DTOU,
+    D3D11_1_SB_OPCODE_ITOD,
+    D3D11_1_SB_OPCODE_UTOD,
+
+// -----------------------------------------------
+
+    // This marks the end of D3D11.1 opcodes
+    D3D11_1_SB_OPCODE_RESERVED0,
+
+    D3DWDDM1_3_SB_OPCODE_GATHER4_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_GATHER4_C_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_GATHER4_PO_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_GATHER4_PO_C_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_LD_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_LD_MS_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_LD_UAV_TYPED_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_LD_RAW_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_LD_STRUCTURED_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_L_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_C_LZ_FEEDBACK,
+
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_CLAMP_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_B_CLAMP_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_D_CLAMP_FEEDBACK,
+    D3DWDDM1_3_SB_OPCODE_SAMPLE_C_CLAMP_FEEDBACK,
+
+    D3DWDDM1_3_SB_OPCODE_CHECK_ACCESS_FULLY_MAPPED,
+
+// -----------------------------------------------
+
+    // This marks the end of WDDM 1.3 opcodes
+    D3DWDDM1_3_SB_OPCODE_RESERVED0,
+
+    D3D10_SB_NUM_OPCODES                                     // Should be the last entry
+} D3D10_SB_OPCODE_TYPE;
+
+#define D3D10_SB_OPCODE_TYPE_MASK 0x00007ff
+// DECODER MACRO: Retrieve program opcode
+#define DECODE_D3D10_SB_OPCODE_TYPE(OpcodeToken0) ((D3D10_SB_OPCODE_TYPE)((OpcodeToken0)&D3D10_SB_OPCODE_TYPE_MASK))
+// ENCODER MACRO: Create the opcode-type portion of OpcodeToken0
+#define ENCODE_D3D10_SB_OPCODE_TYPE(OpcodeName) ((OpcodeName)&D3D10_SB_OPCODE_TYPE_MASK)
+
+#define D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK 0x7f000000
+#define D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT 24
+// DECODER MACRO: Retrieve instruction length
+// in # of DWORDs including the opcode token(s).
+// The range is 1-127.
+#define DECODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(OpcodeToken0) (((OpcodeToken0)&D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK)>> D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT)
+
+// ENCODER MACRO: Store instruction length
+// portion of OpcodeToken0, in # of DWORDs
+// including the opcode token(s).
+// Valid range is 1-127.
+#define ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(Length) (((Length)<<D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT)&D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK)
+#define MAX_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH 127
+
+#define D3D10_SB_INSTRUCTION_SATURATE_MASK 0x00002000
+// DECODER MACRO: Check OpcodeToken0 to see if an instruction
+// is to saturate the result [0..1]
+// This flag is indicated by one of the bits in the
+// opcode specific control range.
+#define DECODE_IS_D3D10_SB_INSTRUCTION_SATURATE_ENABLED(OpcodeToken0) ((OpcodeToken0)&D3D10_SB_INSTRUCTION_SATURATE_MASK)
+// ENCODER MACRO: Encode in OpcodeToken0 if instruction is to saturate the result.
+#define ENCODE_D3D10_SB_INSTRUCTION_SATURATE(bSat) (((bSat)!=0)?D3D10_SB_INSTRUCTION_SATURATE_MASK:0)
+
+// Boolean test for conditional instructions such as if (if_z or if_nz)
+// This is part of the opcode specific control range.
+typedef enum D3D10_SB_INSTRUCTION_TEST_BOOLEAN
+{
+    D3D10_SB_INSTRUCTION_TEST_ZERO       = 0,
+    D3D10_SB_INSTRUCTION_TEST_NONZERO    = 1
+} D3D10_SB_INSTRUCTION_TEST_BOOLEAN;
+#define D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK  0x00040000
+#define D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT 18
+
+// DECODER MACRO: For an OpcodeToken0 for requires either a
+// zero or non-zero test, determine which test was chosen.
+#define DECODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN(OpcodeToken0) ((D3D10_SB_INSTRUCTION_TEST_BOOLEAN)(((OpcodeToken0)&D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK)>>D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT))
+// ENCODER MACRO: Store "zero" or "nonzero" in the opcode
+// specific control range of OpcodeToken0
+#define ENCODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN(Boolean) (((Boolean)<<D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT)&D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK)
+
+// Precise value mask (bits 19-22)
+// This is part of the opcode specific control range.
+// It's 1 bit per-channel of the output, for instructions with multiple
+// output operands, it applies to that component in each operand. This
+// uses the components defined in D3D10_SB_COMPONENT_NAME.
+#define D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK  0x00780000
+#define D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT 19
+
+// DECODER MACRO: this macro extracts from OpcodeToken0 the 4 component
+// (xyzw) mask, as a field of D3D10_SB_4_COMPONENT_[X|Y|Z|W] flags.
+#define DECODE_D3D11_SB_INSTRUCTION_PRECISE_VALUES(OpcodeToken0) ((((OpcodeToken0)&D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK)>>D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT))
+// ENCODER MACRO: Given a set of
+// D3D10_SB_OPERAND_4_COMPONENT_[X|Y|Z|W] values
+// or'd together, encode them in OpcodeToken0.
+#define ENCODE_D3D11_SB_INSTRUCTION_PRECISE_VALUES(ComponentMask) (((ComponentMask)<<D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT)&D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK)
+
+// resinfo instruction return type
+typedef enum D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE
+{
+    D3D10_SB_RESINFO_INSTRUCTION_RETURN_FLOAT      = 0,
+    D3D10_SB_RESINFO_INSTRUCTION_RETURN_RCPFLOAT   = 1,
+    D3D10_SB_RESINFO_INSTRUCTION_RETURN_UINT       = 2
+} D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE;
+
+#define D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK  0x00001800
+#define D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT 11
+
+// DECODER MACRO: For an OpcodeToken0 for the resinfo instruction, 
+// determine the return type.
+#define DECODE_D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE(OpcodeToken0) ((D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE)(((OpcodeToken0)&D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK)>>D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT))
+// ENCODER MACRO: Encode the return type for the resinfo instruction
+// in the opcode specific control range of OpcodeToken0
+#define ENCODE_D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE(ReturnType) (((ReturnType)<<D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT)&D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK)
+
+// sync instruction flags
+#define D3D11_SB_SYNC_THREADS_IN_GROUP              0x00000800
+#define D3D11_SB_SYNC_THREAD_GROUP_SHARED_MEMORY    0x00001000
+#define D3D11_SB_SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP  0x00002000
+#define D3D11_SB_SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GLOBAL  0x00004000
+#define D3D11_SB_SYNC_FLAGS_MASK                    0x00007800
+
+// DECODER MACRO: Retrieve flags for sync instruction from OpcodeToken0.
+#define DECODE_D3D11_SB_SYNC_FLAGS(OperandToken0) ((OperandToken0)&D3D11_SB_SYNC_FLAGS_MASK)
+
+// ENCODER MACRO: Given a set of sync instruciton flags, encode them in OpcodeToken0.
+#define ENCODE_D3D11_SB_SYNC_FLAGS(Flags) ((Flags)&D3D11_SB_SYNC_FLAGS_MASK)
+
+#define D3D10_SB_OPCODE_EXTENDED_MASK 0x80000000
+#define D3D10_SB_OPCODE_EXTENDED_SHIFT 31
+// DECODER MACRO: Determine if the opcode is extended
+// by an additional opcode token.  Currently there are no
+// extended opcodes.
+#define DECODE_IS_D3D10_SB_OPCODE_EXTENDED(OpcodeToken0) (((OpcodeToken0)&D3D10_SB_OPCODE_EXTENDED_MASK)>> D3D10_SB_OPCODE_EXTENDED_SHIFT)
+// ENCODER MACRO: Store in OpcodeToken0 whether the opcode is extended
+// by an additional opcode token.  
+#define ENCODE_D3D10_SB_OPCODE_EXTENDED(bExtended) (((bExtended)!=0)?D3D10_SB_OPCODE_EXTENDED_MASK:0)
+
+// ----------------------------------------------------------------------------
+// Extended Opcode Format (OpcodeToken1)
+//
+// If bit31 of an opcode token is set, the
+// opcode has an additional extended opcode token DWORD
+// directly following OpcodeToken0.  Other tokens
+// expected for the opcode, such as the operand
+// token(s) always follow
+// OpcodeToken0 AND OpcodeToken1..n (extended
+// opcode tokens, if present).
+//
+// [05:00] D3D10_SB_EXTENDED_OPCODE_TYPE
+// [30:06] if([05:00] == D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS)
+//         {
+//              This custom opcode contains controls for SAMPLE.
+//              [08:06] Ignored, 0.
+//              [12:09] U texel immediate offset (4 bit 2's comp) (0 default)
+//              [16:13] V texel immediate offset (4 bit 2's comp) (0 default)
+//              [20:17] W texel immediate offset (4 bit 2's comp) (0 default)
+//              [30:14] Ignored, 0.
+//         }
+//         else if( [05:00] == D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM )
+//         {
+//              [10:06] D3D10_SB_RESOURCE_DIMENSION
+//              [22:11] When dimension is D3D11_SB_RESOURCE_DIMENSION_STRUCTURED_BUFFER this holds the buffer stride, otherwise 0
+//              [30:23] Ignored, 0.
+//         }
+//         else if( [05:00] == D3D11_SB_EXTENDED_OPCODE_RESOURCE_RETURN_TYPE )
+//         {
+//              [09:06] D3D10_SB_RESOURCE_RETURN_TYPE for component X
+//              [13:10] D3D10_SB_RESOURCE_RETURN_TYPE for component Y
+//              [17:14] D3D10_SB_RESOURCE_RETURN_TYPE for component Z
+//              [21:18] D3D10_SB_RESOURCE_RETURN_TYPE for component W
+//              [30:22] Ignored, 0.
+//         }
+//         else
+//         {
+//              [30:04] Ignored, 0.
+//         }
+// [31]    0 normally. 1 there is another extended opcode.  Any number
+//         of extended opcode tokens can be chained.  It is possible that some extended
+//         opcode tokens could include multiple DWORDS - that is defined
+//         on a case by case basis.
+//
+// ----------------------------------------------------------------------------
+typedef enum D3D10_SB_EXTENDED_OPCODE_TYPE
+{
+    D3D10_SB_EXTENDED_OPCODE_EMPTY           = 0,
+    D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS = 1,
+    D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM = 2,
+    D3D11_SB_EXTENDED_OPCODE_RESOURCE_RETURN_TYPE = 3,
+} D3D10_SB_EXTENDED_OPCODE_TYPE;
+#define D3D11_SB_MAX_SIMULTANEOUS_EXTENDED_OPCODES 3
+
+#define D3D10_SB_EXTENDED_OPCODE_TYPE_MASK 0x0000003f
+
+// DECODER MACRO: Given an extended opcode
+// token (OpcodeToken1), figure out what type
+// of token it is (from D3D10_SB_EXTENDED_OPCODE_TYPE enum)
+// to be able to interpret the rest of the token's contents.
+#define DECODE_D3D10_SB_EXTENDED_OPCODE_TYPE(OpcodeToken1) ((D3D10_SB_EXTENDED_OPCODE_TYPE)((OpcodeToken1)&D3D10_SB_EXTENDED_OPCODE_TYPE_MASK))
+
+// ENCODER MACRO: Store extended opcode token
+// type in OpcodeToken1.
+#define ENCODE_D3D10_SB_EXTENDED_OPCODE_TYPE(ExtOpcodeType) ((ExtOpcodeType)&D3D10_SB_EXTENDED_OPCODE_TYPE_MASK)
+
+typedef enum D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD
+{
+    D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_U        = 0,
+    D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_V        = 1,
+    D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_W        = 2,
+} D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD;
+#define D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD_MASK (3)
+#define D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord) (9+4*((Coord)&D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD_MASK))
+#define D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord) (0x0000000f<<D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord))
+
+// DECODER MACRO: Given an extended opcode token
+// (OpcodeToken1), and extended token type ==
+// D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS, determine the immediate
+// texel address offset for u/v/w (D3D10_SB_ADDRESS_OFFSET_COORD)
+// This macro returns a (signed) integer, by sign extending the
+// decoded 4 bit 2's complement immediate value.
+#define DECODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET(Coord,OpcodeToken1) ((((OpcodeToken1)&D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord))>>(D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord))))
+
+// ENCODER MACRO: Store the immediate texel address offset
+// for U or V or W Coord (D3D10_SB_ADDRESS_OFFSET_COORD) in an extended
+// opcode token (OpcodeToken1) that has extended opcode
+// type == D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS (opcode type encoded separately)
+// A 2's complement number is expected as input, from which the LSB 4 bits are extracted.
+#define ENCODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET(Coord,ImmediateOffset) (((ImmediateOffset)<<D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord))&D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord))
+
+#define D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK  0x000007C0
+#define D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT 6
+
+// DECODER MACRO: Given an extended resource declaration token,
+// (D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM), determine the resource dimension
+// (D3D10_SB_RESOURCE_DIMENSION enum)
+#define DECODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION(OpcodeTokenN) ((D3D10_SB_RESOURCE_DIMENSION)(((OpcodeTokenN)&D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK)>>D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT))
+
+// ENCODER MACRO: Store resource dimension
+// (D3D10_SB_RESOURCE_DIMENSION enum) into a
+// an extended resource declaration token (D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM)
+#define ENCODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION(ResourceDim) (((ResourceDim)<<D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT)&D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK)
+
+#define D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK  0x007FF800
+#define D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT 11
+
+// DECODER MACRO: Given an extended resource declaration token for a structured buffer,
+// (D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM), determine the structure stride
+// (12-bit unsigned integer)
+#define DECODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE(OpcodeTokenN) (((OpcodeTokenN)&D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK)>>D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT)
+
+// ENCODER MACRO: Store resource dimension structure stride
+// (12-bit unsigned integer) into a
+// an extended resource declaration token (D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM)
+#define ENCODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE(Stride) (((Stride)<<D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT)&D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK)
+
+#define D3D10_SB_RESOURCE_RETURN_TYPE_MASK    0x0000000f
+#define D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS 0x00000004
+#define D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT 6
+
+// DECODER MACRO: Get the resource return type for component (0-3) from
+// an extended resource declaration token (D3D11_SB_EXTENDED_OPCODE_RESOURCE_RETURN_TYPE)
+#define DECODE_D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE(OpcodeTokenN, Component) \
+    ((D3D10_SB_RESOURCE_RETURN_TYPE)(((OpcodeTokenN) >> \
+    (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS + D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT))&D3D10_SB_RESOURCE_RETURN_TYPE_MASK))
+
+// ENCODER MACRO: Generate a resource return type for a component in an extended
+// resource delcaration token (D3D11_SB_EXTENDED_OPCODE_RESOURCE_RETURN_TYPE)
+#define ENCODE_D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE(ReturnType, Component) \
+    (((ReturnType)&D3D10_SB_RESOURCE_RETURN_TYPE_MASK) << (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS + D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT))
+
+// ----------------------------------------------------------------------------
+// Custom-Data Block Format
+//
+// DWORD 0 (CustomDataDescTok):
+// [10:00] == D3D10_SB_OPCODE_CUSTOMDATA
+// [31:11] == D3D10_SB_CUSTOMDATA_CLASS
+//
+// DWORD 1: 
+//          32-bit unsigned integer count of number
+//          of DWORDs in custom-data block,
+//          including DWORD 0 and DWORD 1.
+//          So the minimum value is 0x00000002,
+//          meaning empty custom-data.
+//
+// Layout of custom-data contents, for the various meta-data classes,
+// not defined in this file.
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_CUSTOMDATA_CLASS
+{
+    D3D10_SB_CUSTOMDATA_COMMENT = 0,
+    D3D10_SB_CUSTOMDATA_DEBUGINFO,
+    D3D10_SB_CUSTOMDATA_OPAQUE,
+    D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER,
+    D3D11_SB_CUSTOMDATA_SHADER_MESSAGE,
+    D3D11_SB_CUSTOMDATA_SHADER_CLIP_PLANE_CONSTANT_MAPPINGS_FOR_DX9,
+} D3D10_SB_CUSTOMDATA_CLASS;
+
+#define D3D10_SB_CUSTOMDATA_CLASS_MASK 0xfffff800
+#define D3D10_SB_CUSTOMDATA_CLASS_SHIFT 11
+// DECODER MACRO: Find out what class of custom-data is present.
+// The contents of the custom-data block are defined
+// for each class of custom-data.
+#define DECODE_D3D10_SB_CUSTOMDATA_CLASS(CustomDataDescTok) ((D3D10_SB_CUSTOMDATA_CLASS)(((CustomDataDescTok)&D3D10_SB_CUSTOMDATA_CLASS_MASK)>>D3D10_SB_CUSTOMDATA_CLASS_SHIFT))
+// ENCODER MACRO: Create complete CustomDataDescTok
+#define ENCODE_D3D10_SB_CUSTOMDATA_CLASS(CustomDataClass) (ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_CUSTOMDATA)|(((CustomDataClass)<<D3D10_SB_CUSTOMDATA_CLASS_SHIFT)&D3D10_SB_CUSTOMDATA_CLASS_MASK))
+
+// ----------------------------------------------------------------------------
+// Instruction Operand Format (OperandToken0)
+//
+// [01:00] D3D10_SB_OPERAND_NUM_COMPONENTS
+// [11:02] Component Selection
+//         if([01:00] == D3D10_SB_OPERAND_0_COMPONENT)
+//              [11:02] = Ignored, 0
+//         else if([01:00] == D3D10_SB_OPERAND_1_COMPONENT
+//              [11:02] = Ignored, 0
+//         else if([01:00] == D3D10_SB_OPERAND_4_COMPONENT
+//         {
+//              [03:02] = D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE
+//              if([03:02] == D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE)
+//              {
+//                  [07:04] = D3D10_SB_OPERAND_4_COMPONENT_MASK
+//                  [11:08] = Ignored, 0
+//              }
+//              else if([03:02] == D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE)
+//              {
+//                  [11:04] = D3D10_SB_4_COMPONENT_SWIZZLE
+//              }
+//              else if([03:02] == D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE)
+//              {
+//                  [05:04] = D3D10_SB_4_COMPONENT_NAME
+//                  [11:06] = Ignored, 0
+//              }
+//         }
+//         else if([01:00] == D3D10_SB_OPERAND_N_COMPONENT)
+//         {
+//              Currently not defined.
+//         }
+// [19:12] D3D10_SB_OPERAND_TYPE
+// [21:20] D3D10_SB_OPERAND_INDEX_DIMENSION:
+//            Number of dimensions in the register
+//            file (NOT the # of dimensions in the
+//            individual register or memory
+//            resource being referenced).
+// [24:22] if( [21:20] >= D3D10_SB_OPERAND_INDEX_1D )
+//             D3D10_SB_OPERAND_INDEX_REPRESENTATION for first operand index
+//         else
+//             Ignored, 0
+// [27:25] if( [21:20] >= D3D10_SB_OPERAND_INDEX_2D )
+//             D3D10_SB_OPERAND_INDEX_REPRESENTATION for second operand index
+//         else
+//             Ignored, 0
+// [30:28] if( [21:20] == D3D10_SB_OPERAND_INDEX_3D )
+//             D3D10_SB_OPERAND_INDEX_REPRESENTATION for third operand index
+//         else
+//             Ignored, 0
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.
+//
+// ----------------------------------------------------------------------------
+
+// Number of components in data vector referred to by operand.
+typedef enum D3D10_SB_OPERAND_NUM_COMPONENTS
+{
+    D3D10_SB_OPERAND_0_COMPONENT = 0,
+    D3D10_SB_OPERAND_1_COMPONENT = 1,
+    D3D10_SB_OPERAND_4_COMPONENT = 2,
+    D3D10_SB_OPERAND_N_COMPONENT = 3 // unused for now
+} D3D10_SB_OPERAND_NUM_COMPONENTS;
+#define D3D10_SB_OPERAND_NUM_COMPONENTS_MASK 0x00000003
+
+// DECODER MACRO: Extract from OperandToken0 how many components
+// the data vector referred to by the operand contains.
+// (D3D10_SB_OPERAND_NUM_COMPONENTS enum)
+#define DECODE_D3D10_SB_OPERAND_NUM_COMPONENTS(OperandToken0) ((D3D10_SB_OPERAND_NUM_COMPONENTS)((OperandToken0)&D3D10_SB_OPERAND_NUM_COMPONENTS_MASK))
+
+// ENCODER MACRO: Define in OperandToken0 how many components
+// the data vector referred to by the operand contains.
+// (D3D10_SB_OPERAND_NUM_COMPONENTS enum).
+#define ENCODE_D3D10_SB_OPERAND_NUM_COMPONENTS(NumComp) ((NumComp)&D3D10_SB_OPERAND_NUM_COMPONENTS_MASK)
+
+typedef enum D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE
+{
+    D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE    = 0,  // mask 4 components
+    D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE = 1,  // swizzle 4 components
+    D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE = 2, // select 1 of 4 components
+} D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE;
+
+#define D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK  0x0000000c
+#define D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT 2
+
+// DECODER MACRO: For an operand representing 4component data,
+// extract from OperandToken0 the method for selecting data from
+// the 4 components (D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE).
+#define DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE(OperandToken0) ((D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE)(((OperandToken0)&D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK)>>D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT))
+
+// ENCODER MACRO: For an operand representing 4component data,
+// encode in OperandToken0 a value from D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE
+#define ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE(SelectionMode) (((SelectionMode)<<D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT)&D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK)
+
+typedef enum D3D10_SB_4_COMPONENT_NAME
+{
+    D3D10_SB_4_COMPONENT_X = 0,
+    D3D10_SB_4_COMPONENT_Y = 1,
+    D3D10_SB_4_COMPONENT_Z = 2,
+    D3D10_SB_4_COMPONENT_W = 3,
+    D3D10_SB_4_COMPONENT_R = 0,
+    D3D10_SB_4_COMPONENT_G = 1,
+    D3D10_SB_4_COMPONENT_B = 2,
+    D3D10_SB_4_COMPONENT_A = 3
+} D3D10_SB_4_COMPONENT_NAME;
+#define D3D10_SB_4_COMPONENT_NAME_MASK 3
+
+// MACROS FOR USE IN D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE:
+
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK   0x000000f0
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_SHIFT  4
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_X      0x00000010
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_Y      0x00000020
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_Z      0x00000040
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_W      0x00000080
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_R      D3D10_SB_OPERAND_4_COMPONENT_MASK_X
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_G      D3D10_SB_OPERAND_4_COMPONENT_MASK_Y
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_B      D3D10_SB_OPERAND_4_COMPONENT_MASK_Z
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_A      D3D10_SB_OPERAND_4_COMPONENT_MASK_W
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK_ALL    D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK
+
+// DECODER MACRO: When 4 component selection mode is
+// D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE, this macro
+// extracts from OperandToken0 the 4 component (xyzw) mask,
+// as a field of D3D10_SB_OPERAND_4_COMPONENT_MASK_[X|Y|Z|W] flags.
+// Alternatively, the D3D10_SB_OPERAND_4_COMPONENT_MASK_[X|Y|Z|W] masks
+// can be tested on OperandToken0 directly, without this macro.
+#define DECODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(OperandToken0) ((OperandToken0)&D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK)
+
+// ENCODER MACRO: Given a set of
+// D3D10_SB_OPERAND_4_COMPONENT_MASK_[X|Y|Z|W] values
+// or'd together, encode them in OperandToken0.
+#define ENCODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(ComponentMask) ((ComponentMask)&D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK)
+
+// ENCODER/DECODER MACRO: Given a D3D10_SB_4_COMPONENT_NAME,
+// generate the 4-component mask for it.
+// This can be used in loops that build masks or read masks.
+// Alternatively, the D3D10_SB_OPERAND_4_COMPONENT_MASK_[X|Y|Z|W] masks
+// can be used directly, without this macro.
+#define D3D10_SB_OPERAND_4_COMPONENT_MASK(ComponentName) ((1<<(D3D10_SB_OPERAND_4_COMPONENT_MASK_SHIFT+ComponentName))&D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK)
+
+// MACROS FOR USE IN D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE:
+
+#define D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MASK 0x00000ff0
+#define D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT 4
+
+// DECODER MACRO: When 4 component selection mode is
+// D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE, this macro
+// extracts from OperandToken0 the 4 component swizzle,
+// as a field of D3D10_SB_OPERAND_4_COMPONENT_MASK_[X|Y|Z|W] flags.
+#define DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(OperandToken0) ((OperandToken0)&D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MASK)
+
+// DECODER MACRO: Pass a D3D10_SB_4_COMPONENT_NAME as "DestComp" in following
+// macro to extract, from OperandToken0 or from a decoded swizzle,
+// the swizzle source component (D3D10_SB_4_COMPONENT_NAME enum):
+#define DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE(OperandToken0,DestComp) ((D3D10_SB_4_COMPONENT_NAME)(((OperandToken0)>>(D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT+2*((DestComp)&D3D10_SB_4_COMPONENT_NAME_MASK)))&D3D10_SB_4_COMPONENT_NAME_MASK))
+
+// ENCODER MACRO: Generate a 4 component swizzle given
+// 4 D3D10_SB_4_COMPONENT_NAME source values for dest
+// components x, y, z, w respectively.
+#define ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(XSrc,YSrc,ZSrc,WSrc) ((((XSrc)&D3D10_SB_4_COMPONENT_NAME_MASK)|     \
+                                                                     (((YSrc)&D3D10_SB_4_COMPONENT_NAME_MASK)<<2)| \
+                                                                     (((ZSrc)&D3D10_SB_4_COMPONENT_NAME_MASK)<<4)| \
+                                                                     (((WSrc)&D3D10_SB_4_COMPONENT_NAME_MASK)<<6)  \
+                                                                      )<<D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT)
+
+// ENCODER/DECODER MACROS: Various common swizzle patterns
+// (noswizzle and replicate of each channels)
+#define D3D10_SB_OPERAND_4_COMPONENT_NOSWIZZLE   ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(D3D10_SB_4_COMPONENT_X,\
+                                                                                   D3D10_SB_4_COMPONENT_Y,\
+                                                                                   D3D10_SB_4_COMPONENT_Z,\
+                                                                                   D3D10_SB_4_COMPONENT_W)
+
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEX  ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(D3D10_SB_4_COMPONENT_X,\
+                                                                                   D3D10_SB_4_COMPONENT_X,\
+                                                                                   D3D10_SB_4_COMPONENT_X,\
+                                                                                   D3D10_SB_4_COMPONENT_X)
+
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEY  ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(D3D10_SB_4_COMPONENT_Y,\
+                                                                                   D3D10_SB_4_COMPONENT_Y,\
+                                                                                   D3D10_SB_4_COMPONENT_Y,\
+                                                                                   D3D10_SB_4_COMPONENT_Y)
+
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEZ  ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(D3D10_SB_4_COMPONENT_Z,\
+                                                                                   D3D10_SB_4_COMPONENT_Z,\
+                                                                                   D3D10_SB_4_COMPONENT_Z,\
+                                                                                   D3D10_SB_4_COMPONENT_Z)
+
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEW  ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(D3D10_SB_4_COMPONENT_W,\
+                                                                                   D3D10_SB_4_COMPONENT_W,\
+                                                                                   D3D10_SB_4_COMPONENT_W,\
+                                                                                   D3D10_SB_4_COMPONENT_W)
+
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATERED    D3D10_SB_OPERAND_4_COMPONENT_REPLICATEX
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEGREEN  D3D10_SB_OPERAND_4_COMPONENT_REPLICATEY
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEBLUE   D3D10_SB_OPERAND_4_COMPONENT_REPLICATEZ
+#define D3D10_SB_OPERAND_4_COMPONENT_REPLICATEALPHA  D3D10_SB_OPERAND_4_COMPONENT_REPLICATEW
+
+// MACROS FOR USE IN D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE:
+#define D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK   0x00000030
+#define D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT  4
+
+// DECODER MACRO: When 4 component selection mode is
+// D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE, this macro
+// extracts from OperandToken0 a D3D10_SB_4_COMPONENT_NAME
+// which picks one of the 4 components.
+#define DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1(OperandToken0) ((D3D10_SB_4_COMPONENT_NAME)(((OperandToken0)&D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK)>>D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT))
+
+// ENCODER MACRO: Given a D3D10_SB_4_COMPONENT_NAME selecting
+// a single component for D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE,
+// encode it into OperandToken0
+#define ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1(SelectedComp) (((SelectedComp)<<D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT)&D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK)
+
+// MACROS FOR DETERMINING OPERAND TYPE:
+
+typedef enum D3D10_SB_OPERAND_TYPE
+{
+    D3D10_SB_OPERAND_TYPE_TEMP           = 0,  // Temporary Register File
+    D3D10_SB_OPERAND_TYPE_INPUT          = 1,  // General Input Register File
+    D3D10_SB_OPERAND_TYPE_OUTPUT         = 2,  // General Output Register File
+    D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP = 3,  // Temporary Register File (indexable)
+    D3D10_SB_OPERAND_TYPE_IMMEDIATE32    = 4,  // 32bit/component immediate value(s)
+                                          // If for example, operand token bits
+                                          // [01:00]==D3D10_SB_OPERAND_4_COMPONENT,
+                                          // this means that the operand type:
+                                          // D3D10_SB_OPERAND_TYPE_IMMEDIATE32
+                                          // results in 4 additional 32bit
+                                          // DWORDS present for the operand.
+    D3D10_SB_OPERAND_TYPE_IMMEDIATE64    = 5,  // 64bit/comp.imm.val(s)HI:LO
+    D3D10_SB_OPERAND_TYPE_SAMPLER        = 6,  // Reference to sampler state
+    D3D10_SB_OPERAND_TYPE_RESOURCE       = 7,  // Reference to memory resource (e.g. texture)
+    D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER= 8,  // Reference to constant buffer
+    D3D10_SB_OPERAND_TYPE_IMMEDIATE_CONSTANT_BUFFER= 9,  // Reference to immediate constant buffer
+    D3D10_SB_OPERAND_TYPE_LABEL          = 10, // Label
+    D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID = 11, // Input primitive ID
+    D3D10_SB_OPERAND_TYPE_OUTPUT_DEPTH   = 12, // Output Depth
+    D3D10_SB_OPERAND_TYPE_NULL           = 13, // Null register, used to discard results of operations
+                                               // Below Are operands new in DX 10.1
+    D3D10_SB_OPERAND_TYPE_RASTERIZER     = 14, // DX10.1 Rasterizer register, used to denote the depth/stencil and render target resources
+    D3D10_SB_OPERAND_TYPE_OUTPUT_COVERAGE_MASK = 15, // DX10.1 PS output MSAA coverage mask (scalar)
+                                               // Below Are operands new in DX 11
+    D3D11_SB_OPERAND_TYPE_STREAM         = 16, // Reference to GS stream output resource
+    D3D11_SB_OPERAND_TYPE_FUNCTION_BODY  = 17, // Reference to a function definition
+    D3D11_SB_OPERAND_TYPE_FUNCTION_TABLE = 18, // Reference to a set of functions used by a class
+    D3D11_SB_OPERAND_TYPE_INTERFACE      = 19, // Reference to an interface
+    D3D11_SB_OPERAND_TYPE_FUNCTION_INPUT = 20, // Reference to an input parameter to a function
+    D3D11_SB_OPERAND_TYPE_FUNCTION_OUTPUT = 21, // Reference to an output parameter to a function
+    D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID = 22, // HS Control Point phase input saying which output control point ID this is
+    D3D11_SB_OPERAND_TYPE_INPUT_FORK_INSTANCE_ID = 23, // HS Fork Phase input instance ID
+    D3D11_SB_OPERAND_TYPE_INPUT_JOIN_INSTANCE_ID = 24, // HS Join Phase input instance ID
+    D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT = 25, // HS Fork+Join, DS phase input control points (array of them)
+    D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT = 26, // HS Fork+Join phase output control points (array of them)
+    D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT = 27, // DS+HSJoin Input Patch Constants (array of them)
+    D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT = 28, // DS Input Domain point
+    D3D11_SB_OPERAND_TYPE_THIS_POINTER       = 29, // Reference to an interface this pointer
+    D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW = 30, // Reference to UAV u#
+    D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY = 31, // Reference to Thread Group Shared Memory g#
+    D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID = 32, // Compute Shader Thread ID
+    D3D11_SB_OPERAND_TYPE_INPUT_THREAD_GROUP_ID = 33, // Compute Shader Thread Group ID
+    D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP = 34, // Compute Shader Thread ID In Thread Group
+    D3D11_SB_OPERAND_TYPE_INPUT_COVERAGE_MASK = 35, // Pixel shader coverage mask input
+    D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED = 36, // Compute Shader Thread ID In Group Flattened to a 1D value.
+    D3D11_SB_OPERAND_TYPE_INPUT_GS_INSTANCE_ID = 37, // Input GS instance ID
+    D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL = 38, // Output Depth, forced to be greater than or equal than current depth
+    D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL    = 39, // Output Depth, forced to be less than or equal to current depth
+    D3D11_SB_OPERAND_TYPE_CYCLE_COUNTER = 40, // Cycle counter
+    D3D11_SB_OPERAND_TYPE_OUTPUT_STENCIL_REF = 41, // DX11 PS output stencil reference (scalar)
+    D3D11_SB_OPERAND_TYPE_INNER_COVERAGE = 42, // DX11 PS input inner coverage (scalar)
+} D3D10_SB_OPERAND_TYPE;
+
+#define D3D10_SB_OPERAND_TYPE_MASK   0x000ff000
+#define D3D10_SB_OPERAND_TYPE_SHIFT  12
+
+// DECODER MACRO: Determine operand type from OperandToken0.
+#define DECODE_D3D10_SB_OPERAND_TYPE(OperandToken0) ((D3D10_SB_OPERAND_TYPE)(((OperandToken0)&D3D10_SB_OPERAND_TYPE_MASK)>>D3D10_SB_OPERAND_TYPE_SHIFT))
+
+// ENCODER MACRO: Store operand type in OperandToken0.
+#define ENCODE_D3D10_SB_OPERAND_TYPE(OperandType) (((OperandType)<<D3D10_SB_OPERAND_TYPE_SHIFT)&D3D10_SB_OPERAND_TYPE_MASK)
+
+typedef enum D3D10_SB_OPERAND_INDEX_DIMENSION
+{
+    D3D10_SB_OPERAND_INDEX_0D = 0, // e.g. Position
+    D3D10_SB_OPERAND_INDEX_1D = 1, // Most common.  e.g. Temp registers.
+    D3D10_SB_OPERAND_INDEX_2D = 2, // e.g. Geometry Program Input registers.
+    D3D10_SB_OPERAND_INDEX_3D = 3, // 3D rarely if ever used.
+} D3D10_SB_OPERAND_INDEX_DIMENSION;
+#define D3D10_SB_OPERAND_INDEX_DIMENSION_MASK  0x00300000
+#define D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT 20
+
+// DECODER MACRO: Determine operand index dimension from OperandToken0.
+#define DECODE_D3D10_SB_OPERAND_INDEX_DIMENSION(OperandToken0) ((D3D10_SB_OPERAND_INDEX_DIMENSION)(((OperandToken0)&D3D10_SB_OPERAND_INDEX_DIMENSION_MASK)>>D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT))
+
+// ENCODER MACRO: Store operand index dimension
+// (D3D10_SB_OPERAND_INDEX_DIMENSION enum) in OperandToken0.
+#define ENCODE_D3D10_SB_OPERAND_INDEX_DIMENSION(OperandIndexDim) (((OperandIndexDim)<<D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT)&D3D10_SB_OPERAND_INDEX_DIMENSION_MASK)
+
+typedef enum D3D10_SB_OPERAND_INDEX_REPRESENTATION
+{
+    D3D10_SB_OPERAND_INDEX_IMMEDIATE32               = 0, // Extra DWORD
+    D3D10_SB_OPERAND_INDEX_IMMEDIATE64               = 1, // 2 Extra DWORDs
+                                                     //   (HI32:LO32)
+    D3D10_SB_OPERAND_INDEX_RELATIVE                  = 2, // Extra operand
+    D3D10_SB_OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE = 3, // Extra DWORD followed by
+                                                     //   extra operand
+    D3D10_SB_OPERAND_INDEX_IMMEDIATE64_PLUS_RELATIVE = 4, // 2 Extra DWORDS
+                                                     //   (HI32:LO32) followed
+                                                     //   by extra operand
+} D3D10_SB_OPERAND_INDEX_REPRESENTATION;
+#define D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim) (22+3*((Dim)&3))
+#define D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim) (0x3<<D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim))
+
+// DECODER MACRO: Determine from OperandToken0 what representation
+// an operand index is provided as (D3D10_SB_OPERAND_INDEX_REPRESENTATION enum),
+// for index dimension [0], [1] or [2], depending on D3D10_SB_OPERAND_INDEX_DIMENSION.
+#define DECODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION(Dim,OperandToken0) ((D3D10_SB_OPERAND_INDEX_REPRESENTATION)(((OperandToken0)&D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim))>>D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim)))
+
+// ENCODER MACRO: Store in OperandToken0 what representation
+// an operand index is provided as (D3D10_SB_OPERAND_INDEX_REPRESENTATION enum),
+// for index dimension [0], [1] or [2], depending on D3D10_SB_OPERAND_INDEX_DIMENSION.
+#define ENCODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION(Dim,IndexRepresentation) (((IndexRepresentation)<<D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim))&D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim))
+
+#define D3D10_SB_OPERAND_EXTENDED_MASK  0x80000000
+#define D3D10_SB_OPERAND_EXTENDED_SHIFT 31
+
+// DECODER MACRO: Determine if the operand is extended
+// by an additional opcode token.
+#define DECODE_IS_D3D10_SB_OPERAND_EXTENDED(OperandToken0) (((OperandToken0)&D3D10_SB_OPERAND_EXTENDED_MASK)>>D3D10_SB_OPERAND_EXTENDED_SHIFT)
+
+// ENCODER MACRO: Store in OperandToken0 whether the operand is extended
+// by an additional operand token.
+#define ENCODE_D3D10_SB_OPERAND_EXTENDED(bExtended) (((bExtended)!=0)?D3D10_SB_OPERAND_EXTENDED_MASK:0)
+
+// ----------------------------------------------------------------------------
+// Extended Instruction Operand Format (OperandToken1)
+//
+// If bit31 of an operand token is set, the
+// operand has additional data in a second DWORD
+// directly following OperandToken0.  Other tokens
+// expected for the operand, such as immmediate
+// values or relative address operands (full
+// operands in themselves) always follow
+// OperandToken0 AND OperandToken1..n (extended
+// operand tokens, if present).
+//
+// [05:00] D3D10_SB_EXTENDED_OPERAND_TYPE
+// [16:06] if([05:00] == D3D10_SB_EXTENDED_OPERAND_MODIFIER)
+//         {
+//              [13:06] D3D10_SB_OPERAND_MODIFIER
+//              [16:14] Min Precision: D3D11_SB_OPERAND_MIN_PRECISION
+//              [17:17] Non-uniform: D3D12_SB_OPERAND_NON_UNIFORM
+//         }
+//         else
+//         {
+//              [17:06] Ignored, 0.
+//         }
+// [30:18] Ignored, 0.
+// [31]    0 normally. 1 if second order extended operand definition,
+//         meaning next DWORD contains yet ANOTHER extended operand
+//         description. Currently no second order extensions defined.
+//         This would be useful if a particular extended operand does
+//         not have enough space to store the required information in
+//         a single token and so is extended further.
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_EXTENDED_OPERAND_TYPE
+{
+    D3D10_SB_EXTENDED_OPERAND_EMPTY            = 0, // Might be used if this
+                                               // enum is full and
+                                               // further extended opcode
+                                               // is needed.
+    D3D10_SB_EXTENDED_OPERAND_MODIFIER         = 1,
+} D3D10_SB_EXTENDED_OPERAND_TYPE;
+#define D3D10_SB_EXTENDED_OPERAND_TYPE_MASK 0x0000003f
+
+// DECODER MACRO: Given an extended operand
+// token (OperandToken1), figure out what type
+// of token it is (from D3D10_SB_EXTENDED_OPERAND_TYPE enum)
+// to be able to interpret the rest of the token's contents.
+#define DECODE_D3D10_SB_EXTENDED_OPERAND_TYPE(OperandToken1) ((D3D10_SB_EXTENDED_OPERAND_TYPE)((OperandToken1)&D3D10_SB_EXTENDED_OPERAND_TYPE_MASK))
+
+// ENCODER MACRO: Store extended operand token
+// type in OperandToken1.
+#define ENCODE_D3D10_SB_EXTENDED_OPERAND_TYPE(ExtOperandType) ((ExtOperandType)&D3D10_SB_EXTENDED_OPERAND_TYPE_MASK)
+
+typedef enum D3D10_SB_OPERAND_MODIFIER
+{
+    D3D10_SB_OPERAND_MODIFIER_NONE     = 0, // Nop.  This is the implied
+                                             // default if the extended
+                                             // operand is not present for
+                                             // an operand for which source
+                                             // modifiers are meaningful
+    D3D10_SB_OPERAND_MODIFIER_NEG      = 1, // Negate
+    D3D10_SB_OPERAND_MODIFIER_ABS      = 2, // Absolute value, abs()
+    D3D10_SB_OPERAND_MODIFIER_ABSNEG   = 3, // -abs()
+} D3D10_SB_OPERAND_MODIFIER;
+#define D3D10_SB_OPERAND_MODIFIER_MASK  0x00003fc0
+#define D3D10_SB_OPERAND_MODIFIER_SHIFT 6
+
+// DECODER MACRO: Given a D3D10_SB_EXTENDED_OPERAND_MODIFIER
+// extended token (OperandToken1), determine the source modifier
+// (D3D10_SB_OPERAND_MODIFIER enum)
+#define DECODE_D3D10_SB_OPERAND_MODIFIER(OperandToken1) ((D3D10_SB_OPERAND_MODIFIER)(((OperandToken1)&D3D10_SB_OPERAND_MODIFIER_MASK)>>D3D10_SB_OPERAND_MODIFIER_SHIFT))
+
+// ENCODER MACRO: Generate a complete source modifier extended token
+// (OperandToken1), given D3D10_SB_OPERAND_MODIFIER enum (the
+// ext. operand type is also set to D3D10_SB_EXTENDED_OPERAND_MODIFIER).
+#define ENCODE_D3D10_SB_EXTENDED_OPERAND_MODIFIER(SourceMod)  ((((SourceMod)<<D3D10_SB_OPERAND_MODIFIER_SHIFT)&D3D10_SB_OPERAND_MODIFIER_MASK)| \
+                                                                ENCODE_D3D10_SB_EXTENDED_OPERAND_TYPE(D3D10_SB_EXTENDED_OPERAND_MODIFIER) | \
+                                                                ENCODE_D3D10_SB_OPERAND_DOUBLE_EXTENDED(0))
+
+// Min precision specifier for source/dest operands.  This 
+// fits in the extended operand token field. Implementations are free to 
+// execute at higher precision than the min - details spec'ed elsewhere.
+// This is part of the opcode specific control range.
+typedef enum D3D11_SB_OPERAND_MIN_PRECISION
+{
+    D3D11_SB_OPERAND_MIN_PRECISION_DEFAULT    = 0, // Default precision 
+                                                       // for the shader model
+    D3D11_SB_OPERAND_MIN_PRECISION_FLOAT_16   = 1, // Min 16 bit/component float
+    D3D11_SB_OPERAND_MIN_PRECISION_FLOAT_2_8  = 2, // Min 10(2.8)bit/comp. float
+    D3D11_SB_OPERAND_MIN_PRECISION_SINT_16    = 4, // Min 16 bit/comp. signed integer
+    D3D11_SB_OPERAND_MIN_PRECISION_UINT_16    = 5, // Min 16 bit/comp. unsigned integer
+} D3D11_SB_OPERAND_MIN_PRECISION;
+#define D3D11_SB_OPERAND_MIN_PRECISION_MASK  0x0001C000
+#define D3D11_SB_OPERAND_MIN_PRECISION_SHIFT 14
+
+// DECODER MACRO: For an OperandToken1 that can specify
+// a minimum precision for execution, find out what it is.
+#define DECODE_D3D11_SB_OPERAND_MIN_PRECISION(OperandToken1) ((D3D11_SB_OPERAND_MIN_PRECISION)(((OperandToken1)& D3D11_SB_OPERAND_MIN_PRECISION_MASK)>> D3D11_SB_OPERAND_MIN_PRECISION_SHIFT))
+
+// ENCODER MACRO: Encode minimum precision for execution
+// into the extended operand token, OperandToken1
+#define ENCODE_D3D11_SB_OPERAND_MIN_PRECISION(MinPrecision) (((MinPrecision)<< D3D11_SB_OPERAND_MIN_PRECISION_SHIFT)& D3D11_SB_OPERAND_MIN_PRECISION_MASK)
+
+
+// Non-uniform extended operand modifier.
+#define D3D12_SB_OPERAND_NON_UNIFORM_MASK  0x00020000
+#define D3D12_SB_OPERAND_NON_UNIFORM_SHIFT 17
+
+// DECODER MACRO: For an OperandToken1 that can specify a non-uniform operand
+#define DECODE_D3D12_SB_OPERAND_NON_UNIFORM(OperandToken1) (((OperandToken1)& D3D12_SB_OPERAND_NON_UNIFORM_MASK)>> D3D12_SB_OPERAND_NON_UNIFORM_SHIFT)
+
+// ENCODER MACRO: Encode non-uniform state into the extended operand token, OperandToken1
+#define ENCODE_D3D12_SB_OPERAND_NON_UNIFORM(NonUniform) (((NonUniform)<< D3D12_SB_OPERAND_NON_UNIFORM_SHIFT)& D3D12_SB_OPERAND_NON_UNIFORM_MASK)
+
+
+#define D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK  0x80000000
+#define D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT 31
+// DECODER MACRO: Determine if an extended operand token
+// (OperandToken1) is further extended by yet another token
+// (OperandToken2).  Currently there are no secondary
+// extended operand tokens.
+#define DECODE_IS_D3D10_SB_OPERAND_DOUBLE_EXTENDED(OperandToken1) (((OperandToken1)&D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK)>>D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT)
+
+// ENCODER MACRO: Store in OperandToken1 whether the operand is extended
+// by an additional operand token.  Currently there are no secondary
+// extended operand tokens.
+#define ENCODE_D3D10_SB_OPERAND_DOUBLE_EXTENDED(bExtended) (((bExtended)!=0)?D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK:0)
+
+// ----------------------------------------------------------------------------
+// Name Token (NameToken) (used in declaration statements)
+//
+// [15:00] D3D10_SB_NAME enumeration
+// [31:16] Reserved, 0
+//
+// ----------------------------------------------------------------------------
+#define D3D10_SB_NAME_MASK  0x0000ffff
+
+// DECODER MACRO: Get the name from NameToken
+#define DECODE_D3D10_SB_NAME(NameToken) ((D3D10_SB_NAME)((NameToken)&D3D10_SB_NAME_MASK))
+
+// ENCODER MACRO: Generate a complete NameToken given a D3D10_SB_NAME
+#define ENCODE_D3D10_SB_NAME(Name) ((Name)&D3D10_SB_NAME_MASK)
+
+//---------------------------------------------------------------------
+// Declaration Statements
+//
+// Declarations start with a standard opcode token,
+// having opcode type being D3D10_SB_OPCODE_DCL*.
+// Each particular declaration type has custom
+// operand token(s), described below.
+//---------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Global Flags Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS
+// [11:11] Refactoring allowed if bit set.
+// [12:12] Enable double precision float ops.
+// [13:13] Force early depth-stencil test.
+// [14:14] Enable RAW and structured buffers in non-CS 4.x shaders.
+// [15:15] Skip optimizations of shader IL when translating to native code
+// [16:16] Enable minimum-precision data types
+// [17:17] Enable 11.1 double-precision floating-point instruction extensions
+// [18:18] Enable 11.1 non-double instruction extensions
+// [23:19] Reserved for future flags.
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by no operands.
+//
+// ----------------------------------------------------------------------------
+#define D3D10_SB_GLOBAL_FLAG_REFACTORING_ALLOWED               (1<<11)
+#define D3D11_SB_GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS (1<<12)
+#define D3D11_SB_GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL         (1<<13)
+#define D3D11_SB_GLOBAL_FLAG_ENABLE_RAW_AND_STRUCTURED_BUFFERS (1<<14)
+#define D3D11_1_SB_GLOBAL_FLAG_SKIP_OPTIMIZATION               (1<<15)
+#define D3D11_1_SB_GLOBAL_FLAG_ENABLE_MINIMUM_PRECISION        (1<<16)
+#define D3D11_1_SB_GLOBAL_FLAG_ENABLE_DOUBLE_EXTENSIONS        (1<<17)
+#define D3D11_1_SB_GLOBAL_FLAG_ENABLE_SHADER_EXTENSIONS        (1<<18)
+#define D3D12_SB_GLOBAL_FLAG_ALL_RESOURCES_BOUND               (1<<19)
+
+#define D3D10_SB_GLOBAL_FLAGS_MASK  0x00fff800
+
+// DECODER MACRO: Get global flags
+#define DECODE_D3D10_SB_GLOBAL_FLAGS(OpcodeToken0) ((OpcodeToken0)&D3D10_SB_GLOBAL_FLAGS_MASK)
+
+// ENCODER MACRO: Encode global flags
+#define ENCODE_D3D10_SB_GLOBAL_FLAGS(Flags) ((Flags)&D3D10_SB_GLOBAL_FLAGS_MASK)
+
+// ----------------------------------------------------------------------------
+// Resource Declaration (non multisampled)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_RESOURCE
+// [15:11] D3D10_SB_RESOURCE_DIMENSION
+// [23:16] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Models 4.0 through 5.0:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+//
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (t<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of resources in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the t# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (t<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of resource within space (may be dynamically indexed)
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+#define D3D10_SB_RESOURCE_DIMENSION_MASK  0x0000F800
+#define D3D10_SB_RESOURCE_DIMENSION_SHIFT 11
+
+// DECODER MACRO: Given a resource declaration token,
+// (OpcodeToken0), determine the resource dimension
+// (D3D10_SB_RESOURCE_DIMENSION enum)
+#define DECODE_D3D10_SB_RESOURCE_DIMENSION(OpcodeToken0) ((D3D10_SB_RESOURCE_DIMENSION)(((OpcodeToken0)&D3D10_SB_RESOURCE_DIMENSION_MASK)>>D3D10_SB_RESOURCE_DIMENSION_SHIFT))
+
+// ENCODER MACRO: Store resource dimension
+// (D3D10_SB_RESOURCE_DIMENSION enum) into a
+// a resource declaration token (OpcodeToken0)
+#define ENCODE_D3D10_SB_RESOURCE_DIMENSION(ResourceDim) (((ResourceDim)<<D3D10_SB_RESOURCE_DIMENSION_SHIFT)&D3D10_SB_RESOURCE_DIMENSION_MASK)
+
+// ----------------------------------------------------------------------------
+// Resource Declaration (multisampled)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_RESOURCE (same opcode as non-multisampled case)
+// [15:11] D3D10_SB_RESOURCE_DIMENSION (must be TEXTURE2DMS or TEXTURE2DMSARRAY)
+// [22:16] Sample count 1...127.  0 is currently disallowed, though
+//         in future versions 0 could mean "configurable" sample count
+// [23:23] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Models 4.0 through 5.0:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+//
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (t<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of resources in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the t# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (t<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of resource within space (may be dynamically indexed)
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+
+// use same macro for encoding/decoding resource dimension aas the non-msaa declaration
+
+#define D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK  0x07F0000
+#define D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT 16
+
+// DECODER MACRO: Given a resource declaration token,
+// (OpcodeToken0), determine the resource sample count (1..127)
+#define DECODE_D3D10_SB_RESOURCE_SAMPLE_COUNT(OpcodeToken0) ((UINT)(((OpcodeToken0)&D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK)>>D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT))
+
+// ENCODER MACRO: Store resource sample count up to 127 into a
+// a resource declaration token (OpcodeToken0)
+#define ENCODE_D3D10_SB_RESOURCE_SAMPLE_COUNT(SampleCount) (((SampleCount > 127 ? 127 : SampleCount)<<D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT)&D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK)
+
+// ----------------------------------------------------------------------------
+// Resource Return Type Token (ResourceReturnTypeToken) (used in resource
+// declaration statements)
+//
+// [03:00] D3D10_SB_RESOURCE_RETURN_TYPE for component X
+// [07:04] D3D10_SB_RESOURCE_RETURN_TYPE for component Y
+// [11:08] D3D10_SB_RESOURCE_RETURN_TYPE for component Z
+// [15:12] D3D10_SB_RESOURCE_RETURN_TYPE for component W
+// [31:16] Reserved, 0
+//
+// ----------------------------------------------------------------------------
+// DECODER MACRO: Get the resource return type for component (0-3) from
+// ResourceReturnTypeToken
+#define DECODE_D3D10_SB_RESOURCE_RETURN_TYPE(ResourceReturnTypeToken, Component) \
+    ((D3D10_SB_RESOURCE_RETURN_TYPE)(((ResourceReturnTypeToken) >> \
+    (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS))&D3D10_SB_RESOURCE_RETURN_TYPE_MASK))
+
+// ENCODER MACRO: Generate a resource return type for a component
+#define ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE(ReturnType, Component) \
+    (((ReturnType)&D3D10_SB_RESOURCE_RETURN_TYPE_MASK) << (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS))
+
+// ----------------------------------------------------------------------------
+// Sampler Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_SAMPLER
+// [14:11] D3D10_SB_SAMPLER_MODE
+// [23:15] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand on Shader Models 4.0 through 5.0:
+// (1) Operand starting with OperandToken0, defining which sampler
+//     (D3D10_SB_OPERAND_TYPE_SAMPLER) register # is being declared.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     s# register (D3D10_SB_OPERAND_TYPE_SAMPLER) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (s<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of samplers in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the s# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (s<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of sampler within space (may be dynamically indexed)
+// (2) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+typedef enum D3D10_SB_SAMPLER_MODE
+{
+    D3D10_SB_SAMPLER_MODE_DEFAULT      = 0,
+    D3D10_SB_SAMPLER_MODE_COMPARISON   = 1,
+    D3D10_SB_SAMPLER_MODE_MONO         = 2,
+} D3D10_SB_SAMPLER_MODE;
+
+#define D3D10_SB_SAMPLER_MODE_MASK  0x00007800
+#define D3D10_SB_SAMPLER_MODE_SHIFT 11
+
+// DECODER MACRO: Find out if a Constant Buffer is going to be indexed or not
+#define DECODE_D3D10_SB_SAMPLER_MODE(OpcodeToken0) ((D3D10_SB_SAMPLER_MODE)(((OpcodeToken0)&D3D10_SB_SAMPLER_MODE_MASK)>>D3D10_SB_SAMPLER_MODE_SHIFT))
+
+// ENCODER MACRO: Generate a resource return type for a component
+#define ENCODE_D3D10_SB_SAMPLER_MODE(SamplerMode) (((SamplerMode)<<D3D10_SB_SAMPLER_MODE_SHIFT)&D3D10_SB_SAMPLER_MODE_MASK)
+
+// ----------------------------------------------------------------------------
+// Input Register Declaration (see separate declarations for Pixel Shaders)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared, 
+//     including writemask.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Input Register Declaration w/System Interpreted Value
+// (see separate declarations for Pixel Shaders)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT_SIV
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared,
+//     including writemask.  For Geometry Shaders, the input is 
+//     v[vertex][attribute], and this declaration is only for which register 
+//     on the attribute axis is being declared.  The vertex axis value must 
+//     be equal to the # of vertices in the current input primitive for the GS
+//     (i.e. 6 for triangle + adjacency).
+// (2) a System Interpreted Value Name (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Input Register Declaration w/System Generated Value
+// (available for all shaders incl. Pixel Shader, no interpolation mode needed)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT_SGV
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared,
+//     including writemask.
+// (2) a System Generated Value Name (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Pixel Shader Input Register Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT_PS
+// [14:11] D3D10_SB_INTERPOLATION_MODE
+// [23:15] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared,
+//     including writemask.
+//
+// ----------------------------------------------------------------------------
+#define D3D10_SB_INPUT_INTERPOLATION_MODE_MASK  0x00007800
+#define D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT 11
+
+// DECODER MACRO: Find out interpolation mode for the input register
+#define DECODE_D3D10_SB_INPUT_INTERPOLATION_MODE(OpcodeToken0) ((D3D10_SB_INTERPOLATION_MODE)(((OpcodeToken0)&D3D10_SB_INPUT_INTERPOLATION_MODE_MASK)>>D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT))
+
+// ENCODER MACRO: Encode interpolation mode for a register.
+#define ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE(InterpolationMode) (((InterpolationMode)<<D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT)&D3D10_SB_INPUT_INTERPOLATION_MODE_MASK)
+
+// ----------------------------------------------------------------------------
+// Pixel Shader Input Register Declaration w/System Interpreted Value
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT_PS_SIV
+// [14:11] D3D10_SB_INTERPOLATION_MODE
+// [23:15] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared.
+// (2) a System Interpreted Value Name (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Pixel Shader Input Register Declaration w/System Generated Value
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INPUT_PS_SGV
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) Operand, starting with OperandToken0, defining which input
+//     v# register (D3D10_SB_OPERAND_TYPE_INPUT) is being declared.
+// (2) a System Generated Value Name (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Output Register Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_OUTPUT
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand:
+// (1) Operand, starting with OperandToken0, defining which
+//     o# register (D3D10_SB_OPERAND_TYPE_OUTPUT) is being declared,
+//     including writemask.
+//     (in Pixel Shader, output can also be one of 
+//     D3D10_SB_OPERAND_TYPE_OUTPUT_DEPTH,
+//     D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL, or
+//     D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL )
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Output Register Declaration w/System Interpreted Value
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_OUTPUT_SIV
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     o# register (D3D10_SB_OPERAND_TYPE_OUTPUT) is being declared,
+//     including writemask.
+// (2) a System Interpreted Name token (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Output Register Declaration w/System Generated Value
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_OUTPUT_SGV
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     o# register (D3D10_SB_OPERAND_TYPE_OUTPUT) is being declared,
+//     including writemask.
+// (2) a System Generated Name token (NameToken)
+//
+// ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// Input or Output Register Indexing Range Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INDEX_RANGE
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     input (v#) or output (o#) register is having its array indexing range
+//     declared, including writemask.  For Geometry Shader inputs, 
+//     it is assumed that the vertex axis is always fully indexable,
+//     and 0 must be specified as the vertex# in this declaration, so that 
+//     only the a range of attributes are having their index range defined.
+//     
+// (2) a DWORD representing the count of registers starting from the one
+//     indicated in (1).
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Temp Register Declaration r0...r(n-1) 
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_TEMPS
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand:
+// (1) DWORD (unsigned int) indicating how many temps are being declared.  
+//     i.e. 5 means r0...r4 are declared.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Indexable Temp Register (x#[size]) Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 3 DWORDs:
+// (1) Register index (defines which x# register is declared)
+// (2) Number of registers in this register bank
+// (3) Number of components in the array (1-4). 1 means .x, 2 means .xy etc.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Constant Buffer Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER
+// [11]    D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN
+// [23:12] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand on Shader Model 4.0 through 5.0:
+// (1) Operand, starting with OperandToken0, defining which CB slot (cb#[size])
+//     is being declared. (operand type: D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER)
+//     The indexing dimension for the register must be 
+//     D3D10_SB_OPERAND_INDEX_DIMENSION_2D, where the first index specifies
+//     which cb#[] is being declared, and the second (array) index specifies the size 
+//     of the buffer, as a count of 32-bit*4 elements.  (As opposed to when the 
+//     cb#[] is used in shader instructions, and the array index represents which 
+//     location in the constant buffer is being referenced.)
+//     If the size is specified as 0, the CB size is not known (any size CB
+//     can be bound to the slot).
+//
+// The order of constant buffer declarations in a shader indicates their
+// relative priority from highest to lowest (hint to driver).
+// 
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) Operand, starting with OperandToken0, defining which CB range (ID and bounds)
+//     is being declared. (operand type: D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER)
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (cb<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of constant buffers in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the cb#[] is used in shader instructions: (cb<id>[<idx>][<loc>])
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of constant buffer within space (may be dynamically indexed)
+//       3 <loc>: location of vector within constant buffer being referenced,
+//          which may also be dynamically indexed, with no access pattern flag required.
+// (2) a DWORD indicating the size of the constant buffer as a count of 16-byte vectors.
+//     Each vector is 32-bit*4 elements == 128-bits == 16 bytes.
+//     If the size is specified as 0, the CB size is not known (any size CB
+//     can be bound to the slot).
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN
+{
+    D3D10_SB_CONSTANT_BUFFER_IMMEDIATE_INDEXED  = 0,
+    D3D10_SB_CONSTANT_BUFFER_DYNAMIC_INDEXED    = 1
+} D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN;
+
+#define D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK  0x00000800
+#define D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT 11
+
+// DECODER MACRO: Find out if a Constant Buffer is going to be indexed or not
+#define DECODE_D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN(OpcodeToken0) ((D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN)(((OpcodeToken0)&D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK)>>D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT))
+
+// ENCODER MACRO: Encode the access pattern for the Constant Buffer
+#define ENCODE_D3D10_SB_D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN(AccessPattern) (((AccessPattern)<<D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT)&D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK)
+
+// ----------------------------------------------------------------------------
+// Immediate Constant Buffer Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_CUSTOMDATA
+// [31:11] == D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER
+//
+// OpcodeToken0 is followed by:
+// (1) DWORD indicating length of declaration, including OpcodeToken0.
+//     This length must = 2(for OpcodeToken0 and 1) + a multiple of 4 
+//                                                    (# of immediate constants)
+// (2) Sequence of 4-tuples of DWORDs defining the Immediate Constant Buffer.
+//     The number of 4-tuples is (length above - 1) / 4
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Shader Message Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_CUSTOMDATA
+// [31:11] == D3D11_SB_CUSTOMDATA_SHADER_MESSAGE
+//
+// OpcodeToken0 is followed by:
+// (1) DWORD indicating length of declaration, including OpcodeToken0.
+// (2) DWORD (D3D11_SB_SHADER_MESSAGE_ID) indicating shader message or error.
+// (3) D3D11_SB_SHADER_MESSAGE_FORMAT indicating the convention for formatting the message.
+// (4) DWORD indicating the number of characters in the string without the terminator.
+// (5) DWORD indicating the number of operands.
+// (6) DWORD indicating length of operands.
+// (7) Encoded operands.
+// (8) String with trailing zero, padded to a multiple of DWORDs.
+//     The string is in the given format and the operands given should
+//     be used for argument substitutions when formatting.
+// ----------------------------------------------------------------------------
+
+typedef enum D3D11_SB_SHADER_MESSAGE_ID
+{
+    D3D11_SB_SHADER_MESSAGE_ID_MESSAGE = 0x00200102,
+    D3D11_SB_SHADER_MESSAGE_ID_ERROR = 0x00200103
+} D3D11_SB_SHADER_MESSAGE_ID;
+
+typedef enum D3D11_SB_SHADER_MESSAGE_FORMAT
+{
+    // No formatting, just a text string.  Operands are ignored.
+    D3D11_SB_SHADER_MESSAGE_FORMAT_ANSI_TEXT,
+    // Format string follows C/C++ printf conventions.
+    D3D11_SB_SHADER_MESSAGE_FORMAT_ANSI_PRINTF,
+} D3D11_SB_SHADER_MESSAGE_FORMAT;
+
+// ----------------------------------------------------------------------------
+// Shader Clip Plane Constant Mappings for DX9 hardware
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_CUSTOMDATA
+// [31:11] == D3D11_SB_CUSTOMDATA_SHADER_CLIP_PLANE_CONSTANT_MAPPINGS_FOR_DX9
+//
+// OpcodeToken0 is followed by:
+// (1) DWORD indicating length of declaration, including OpcodeToken0.
+// (2) DWORD indicating number of constant mappings (up to 6 mappings).
+// (3+) Constant mapping tables in following format.
+//
+// struct _Clip_Plane_Constant_Mapping
+// {
+//     WORD ConstantBufferIndex;  // cb[n]
+//     WORD StartConstantElement; // starting index of cb[n][m]
+//     WORD ConstantElemntCount;  // number of elements cb[n][m] ~ cb[n][m+l]
+//     WORD Reserved;             //
+// };
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Geometry Shader Input Primitive Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE
+// [16:11] D3D10_SB_PRIMITIVE [not D3D10_SB_PRIMITIVE_TOPOLOGY]
+// [23:17] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+
+#define D3D10_SB_GS_INPUT_PRIMITIVE_MASK  0x0001f800
+#define D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT 11
+
+// DECODER MACRO: Given a primitive topology declaration,
+// (OpcodeToken0), determine the primitive topology
+// (D3D10_SB_PRIMITIVE enum)
+#define DECODE_D3D10_SB_GS_INPUT_PRIMITIVE(OpcodeToken0) ((D3D10_SB_PRIMITIVE)(((OpcodeToken0)&D3D10_SB_GS_INPUT_PRIMITIVE_MASK)>>D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT))
+
+// ENCODER MACRO: Store primitive topology
+// (D3D10_SB_PRIMITIVE enum) into a
+// a primitive topology declaration token (OpcodeToken0)
+#define ENCODE_D3D10_SB_GS_INPUT_PRIMITIVE(Prim) (((Prim)<<D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT)&D3D10_SB_GS_INPUT_PRIMITIVE_MASK)
+
+// ----------------------------------------------------------------------------
+// Geometry Shader Output Topology Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY
+// [17:11] D3D10_SB_PRIMITIVE_TOPOLOGY
+// [23:18] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+
+#define D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK  0x0001f800
+#define D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT 11
+
+// DECODER MACRO: Given a primitive topology declaration,
+// (OpcodeToken0), determine the primitive topology
+// (D3D10_SB_PRIMITIVE_TOPOLOGY enum)
+#define DECODE_D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY(OpcodeToken0) ((D3D10_SB_PRIMITIVE_TOPOLOGY)(((OpcodeToken0)&D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK)>>D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT))
+
+// ENCODER MACRO: Store primitive topology
+// (D3D10_SB_PRIMITIVE_TOPOLOGY enum) into a
+// a primitive topology declaration token (OpcodeToken0)
+#define ENCODE_D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY(PrimTopology) (((PrimTopology)<<D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT)&D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK)
+
+// ----------------------------------------------------------------------------
+// Geometry Shader Maximum Output Vertex Count Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by a DWORD representing the
+// maximum number of primitives that could be output
+// by the Geometry Shader.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Geometry Shader Instance Count Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_GS_INSTANCE_COUNT
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by a UINT32 representing the
+// number of instances of the geometry shader program to execute.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: HS/DS Input Control Point Count
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT
+// [16:11] Control point count 
+// [23:17] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+#define D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK  0x0001f800
+#define D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT 11
+
+// DECODER MACRO: Given an input control point count declaration token,
+// (OpcodeToken0), determine the control point count
+#define DECODE_D3D11_SB_INPUT_CONTROL_POINT_COUNT(OpcodeToken0) ((UINT)(((OpcodeToken0)&D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK)>>D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT))
+
+// ENCODER MACRO: Store input control point count into a declaration token
+#define ENCODE_D3D11_SB_INPUT_CONTROL_POINT_COUNT(Count) (((Count)<<D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT)&D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK)
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: HS Output Control Point Count
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT
+// [16:11] Control point count 
+// [23:17] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+#define D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK  0x0001f800
+#define D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT 11
+
+// DECODER MACRO: Given an output control point count declaration token,
+// (OpcodeToken0), determine the control point count
+#define DECODE_D3D11_SB_OUTPUT_CONTROL_POINT_COUNT(OpcodeToken0) ((UINT)(((OpcodeToken0)&D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK)>>D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT))
+
+// ENCODER MACRO: Store output control point count into a declaration token
+#define ENCODE_D3D11_SB_OUTPUT_CONTROL_POINT_COUNT(Count) (((Count)<<D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT)&D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK)
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: Tessellator Domain
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_TESS_DOMAIN
+// [12:11] Domain
+// [23:13] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+typedef enum D3D11_SB_TESSELLATOR_DOMAIN
+{
+    D3D11_SB_TESSELLATOR_DOMAIN_UNDEFINED = 0,
+    D3D11_SB_TESSELLATOR_DOMAIN_ISOLINE   = 1,
+    D3D11_SB_TESSELLATOR_DOMAIN_TRI       = 2,
+    D3D11_SB_TESSELLATOR_DOMAIN_QUAD      = 3
+} D3D11_SB_TESSELLATOR_DOMAIN;
+
+#define D3D11_SB_TESS_DOMAIN_MASK  0x00001800
+#define D3D11_SB_TESS_DOMAIN_SHIFT 11
+
+// DECODER MACRO: Given a tessellator domain declaration,
+// (OpcodeToken0), determine the domain
+// (D3D11_SB_TESSELLATOR_DOMAIN enum)
+#define DECODE_D3D11_SB_TESS_DOMAIN(OpcodeToken0) ((D3D11_SB_TESSELLATOR_DOMAIN)(((OpcodeToken0)&D3D11_SB_TESS_DOMAIN_MASK)>>D3D11_SB_TESS_DOMAIN_SHIFT))
+
+// ENCODER MACRO: Store tessellator domain
+// (D3D11_SB_TESSELLATOR_DOMAIN enum) into a
+// a tessellator domain declaration token (OpcodeToken0)
+#define ENCODE_D3D11_SB_TESS_DOMAIN(Domain) (((Domain)<<D3D11_SB_TESS_DOMAIN_SHIFT)&D3D11_SB_TESS_DOMAIN_MASK)
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: Tessellator Partitioning
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_TESS_PARTITIONING
+// [13:11] Partitioning
+// [23:14] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+typedef enum D3D11_SB_TESSELLATOR_PARTITIONING
+{
+    D3D11_SB_TESSELLATOR_PARTITIONING_UNDEFINED       = 0,
+    D3D11_SB_TESSELLATOR_PARTITIONING_INTEGER         = 1,
+    D3D11_SB_TESSELLATOR_PARTITIONING_POW2            = 2,
+    D3D11_SB_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD  = 3,
+    D3D11_SB_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 4
+} D3D11_SB_TESSELLATOR_PARTITIONING;
+
+#define D3D11_SB_TESS_PARTITIONING_MASK  0x00003800
+#define D3D11_SB_TESS_PARTITIONING_SHIFT 11
+
+// DECODER MACRO: Given a tessellator partitioning declaration,
+// (OpcodeToken0), determine the domain
+// (D3D11_SB_TESSELLATOR_PARTITIONING enum)
+#define DECODE_D3D11_SB_TESS_PARTITIONING(OpcodeToken0) ((D3D11_SB_TESSELLATOR_PARTITIONING)(((OpcodeToken0)&D3D11_SB_TESS_PARTITIONING_MASK)>>D3D11_SB_TESS_PARTITIONING_SHIFT))
+
+// ENCODER MACRO: Store tessellator partitioning
+// (D3D11_SB_TESSELLATOR_PARTITIONING enum) into a
+// a tessellator partitioning declaration token (OpcodeToken0)
+#define ENCODE_D3D11_SB_TESS_PARTITIONING(Partitioning) (((Partitioning)<<D3D11_SB_TESS_PARTITIONING_SHIFT)&D3D11_SB_TESS_PARTITIONING_MASK)
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: Tessellator Output Primitive
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE
+// [13:11] Output Primitive
+// [23:14] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token. == 1
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// ----------------------------------------------------------------------------
+typedef enum D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE
+{
+    D3D11_SB_TESSELLATOR_OUTPUT_UNDEFINED     = 0,
+    D3D11_SB_TESSELLATOR_OUTPUT_POINT         = 1,
+    D3D11_SB_TESSELLATOR_OUTPUT_LINE          = 2,
+    D3D11_SB_TESSELLATOR_OUTPUT_TRIANGLE_CW   = 3,
+    D3D11_SB_TESSELLATOR_OUTPUT_TRIANGLE_CCW  = 4
+} D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE;
+
+#define D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK  0x00003800
+#define D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT 11
+
+// DECODER MACRO: Given a tessellator output primitive declaration,
+// (OpcodeToken0), determine the domain
+// (D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE enum)
+#define DECODE_D3D11_SB_TESS_OUTPUT_PRIMITIVE(OpcodeToken0) ((D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE)(((OpcodeToken0)&D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK)>>D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT))
+
+// ENCODER MACRO: Store tessellator output primitive
+// (D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE enum) into a
+// a tessellator output primitive declaration token (OpcodeToken0)
+#define ENCODE_D3D11_SB_TESS_OUTPUT_PRIMITIVE(OutputPrimitive) (((OutputPrimitive)<<D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT)&D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK)
+
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: Hull Shader Max Tessfactor
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_HS_MAX_TESSFACTOR
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by a float32 representing the
+// maximum TessFactor.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Hull Shader Declaration Phase: Hull Shader Fork Phase Instance Count
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by a UINT32 representing the
+// number of instances of the current fork phase program to execute.
+//
+// ----------------------------------------------------------------------------
+
+typedef enum D3D10_SB_INTERPOLATION_MODE
+{
+    D3D10_SB_INTERPOLATION_UNDEFINED = 0,
+    D3D10_SB_INTERPOLATION_CONSTANT = 1,
+    D3D10_SB_INTERPOLATION_LINEAR = 2,
+    D3D10_SB_INTERPOLATION_LINEAR_CENTROID = 3,
+    D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE = 4,
+    D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID = 5,
+    D3D10_SB_INTERPOLATION_LINEAR_SAMPLE = 6, // DX10.1
+    D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE = 7, // DX10.1
+} D3D10_SB_INTERPOLATION_MODE;
+
+// Keep PRIMITIVE_TOPOLOGY values in sync with earlier DX versions (HW consumes values directly).
+typedef enum D3D10_SB_PRIMITIVE_TOPOLOGY
+{
+    D3D10_SB_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_LINELIST = 2,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
+    // 6 is reserved for legacy triangle fans
+    // Adjacency values should be equal to (0x8 & non-adjacency):
+    D3D10_SB_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
+    D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
+} D3D10_SB_PRIMITIVE_TOPOLOGY;
+
+typedef enum D3D10_SB_PRIMITIVE
+{
+    D3D10_SB_PRIMITIVE_UNDEFINED = 0,
+    D3D10_SB_PRIMITIVE_POINT = 1,
+    D3D10_SB_PRIMITIVE_LINE = 2,
+    D3D10_SB_PRIMITIVE_TRIANGLE = 3,
+    // Adjacency values should be equal to (0x4 & non-adjacency):
+    D3D10_SB_PRIMITIVE_LINE_ADJ = 6,
+    D3D10_SB_PRIMITIVE_TRIANGLE_ADJ = 7,
+    D3D11_SB_PRIMITIVE_1_CONTROL_POINT_PATCH = 8,
+    D3D11_SB_PRIMITIVE_2_CONTROL_POINT_PATCH = 9,
+    D3D11_SB_PRIMITIVE_3_CONTROL_POINT_PATCH = 10,
+    D3D11_SB_PRIMITIVE_4_CONTROL_POINT_PATCH = 11,
+    D3D11_SB_PRIMITIVE_5_CONTROL_POINT_PATCH = 12,
+    D3D11_SB_PRIMITIVE_6_CONTROL_POINT_PATCH = 13,
+    D3D11_SB_PRIMITIVE_7_CONTROL_POINT_PATCH = 14,
+    D3D11_SB_PRIMITIVE_8_CONTROL_POINT_PATCH = 15,
+    D3D11_SB_PRIMITIVE_9_CONTROL_POINT_PATCH = 16,
+    D3D11_SB_PRIMITIVE_10_CONTROL_POINT_PATCH = 17,
+    D3D11_SB_PRIMITIVE_11_CONTROL_POINT_PATCH = 18,
+    D3D11_SB_PRIMITIVE_12_CONTROL_POINT_PATCH = 19,
+    D3D11_SB_PRIMITIVE_13_CONTROL_POINT_PATCH = 20,
+    D3D11_SB_PRIMITIVE_14_CONTROL_POINT_PATCH = 21,
+    D3D11_SB_PRIMITIVE_15_CONTROL_POINT_PATCH = 22,
+    D3D11_SB_PRIMITIVE_16_CONTROL_POINT_PATCH = 23,
+    D3D11_SB_PRIMITIVE_17_CONTROL_POINT_PATCH = 24,
+    D3D11_SB_PRIMITIVE_18_CONTROL_POINT_PATCH = 25,
+    D3D11_SB_PRIMITIVE_19_CONTROL_POINT_PATCH = 26,
+    D3D11_SB_PRIMITIVE_20_CONTROL_POINT_PATCH = 27,
+    D3D11_SB_PRIMITIVE_21_CONTROL_POINT_PATCH = 28,
+    D3D11_SB_PRIMITIVE_22_CONTROL_POINT_PATCH = 29,
+    D3D11_SB_PRIMITIVE_23_CONTROL_POINT_PATCH = 30,
+    D3D11_SB_PRIMITIVE_24_CONTROL_POINT_PATCH = 31,
+    D3D11_SB_PRIMITIVE_25_CONTROL_POINT_PATCH = 32,
+    D3D11_SB_PRIMITIVE_26_CONTROL_POINT_PATCH = 33,
+    D3D11_SB_PRIMITIVE_27_CONTROL_POINT_PATCH = 34,
+    D3D11_SB_PRIMITIVE_28_CONTROL_POINT_PATCH = 35,
+    D3D11_SB_PRIMITIVE_29_CONTROL_POINT_PATCH = 36,
+    D3D11_SB_PRIMITIVE_30_CONTROL_POINT_PATCH = 37,
+    D3D11_SB_PRIMITIVE_31_CONTROL_POINT_PATCH = 38,
+    D3D11_SB_PRIMITIVE_32_CONTROL_POINT_PATCH = 39,
+} D3D10_SB_PRIMITIVE;
+
+typedef enum D3D10_SB_COMPONENT_MASK
+{
+    D3D10_SB_COMPONENT_MASK_X = 1,
+    D3D10_SB_COMPONENT_MASK_Y = 2,
+    D3D10_SB_COMPONENT_MASK_Z = 4,
+    D3D10_SB_COMPONENT_MASK_W = 8,
+    D3D10_SB_COMPONENT_MASK_R = 1,
+    D3D10_SB_COMPONENT_MASK_G = 2,
+    D3D10_SB_COMPONENT_MASK_B = 4,
+    D3D10_SB_COMPONENT_MASK_A = 8,
+    D3D10_SB_COMPONENT_MASK_ALL = 15,
+} D3D10_SB_COMPONENT_MASK;
+
+typedef enum D3D10_SB_NAME
+{
+    D3D10_SB_NAME_UNDEFINED = 0,
+    D3D10_SB_NAME_POSITION = 1,
+    D3D10_SB_NAME_CLIP_DISTANCE = 2,
+    D3D10_SB_NAME_CULL_DISTANCE = 3,
+    D3D10_SB_NAME_RENDER_TARGET_ARRAY_INDEX = 4,
+    D3D10_SB_NAME_VIEWPORT_ARRAY_INDEX = 5,
+    D3D10_SB_NAME_VERTEX_ID = 6,
+    D3D10_SB_NAME_PRIMITIVE_ID = 7,
+    D3D10_SB_NAME_INSTANCE_ID = 8,
+    D3D10_SB_NAME_IS_FRONT_FACE = 9,
+    D3D10_SB_NAME_SAMPLE_INDEX = 10,
+    // The following are added for D3D11
+    D3D11_SB_NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR = 11, 
+    D3D11_SB_NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR = 12, 
+    D3D11_SB_NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR = 13, 
+    D3D11_SB_NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR = 14, 
+    D3D11_SB_NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR = 15, 
+    D3D11_SB_NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR = 16, 
+    D3D11_SB_NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR = 17, 
+    D3D11_SB_NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR = 18, 
+    D3D11_SB_NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR = 19, 
+    D3D11_SB_NAME_FINAL_TRI_INSIDE_TESSFACTOR = 20, 
+    D3D11_SB_NAME_FINAL_LINE_DETAIL_TESSFACTOR = 21,
+    D3D11_SB_NAME_FINAL_LINE_DENSITY_TESSFACTOR = 22,
+    // The following are added for D3D12
+    D3D12_SB_NAME_BARYCENTRICS = 23,
+    D3D12_SB_NAME_SHADINGRATE = 24,
+    D3D12_SB_NAME_CULLPRIMITIVE = 25,
+} D3D10_SB_NAME;
+
+typedef enum D3D10_SB_RESOURCE_DIMENSION
+{
+    D3D10_SB_RESOURCE_DIMENSION_UNKNOWN = 0,
+    D3D10_SB_RESOURCE_DIMENSION_BUFFER = 1,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE1D = 2,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE2D = 3,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DMS = 4,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE3D = 5,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURECUBE = 6,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE1DARRAY = 7,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DARRAY = 8,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DMSARRAY = 9,
+    D3D10_SB_RESOURCE_DIMENSION_TEXTURECUBEARRAY = 10,
+    D3D11_SB_RESOURCE_DIMENSION_RAW_BUFFER = 11,
+    D3D11_SB_RESOURCE_DIMENSION_STRUCTURED_BUFFER = 12,
+} D3D10_SB_RESOURCE_DIMENSION;
+
+typedef enum D3D10_SB_RESOURCE_RETURN_TYPE
+{
+    D3D10_SB_RETURN_TYPE_UNORM = 1,
+    D3D10_SB_RETURN_TYPE_SNORM = 2,
+    D3D10_SB_RETURN_TYPE_SINT = 3,
+    D3D10_SB_RETURN_TYPE_UINT = 4,
+    D3D10_SB_RETURN_TYPE_FLOAT = 5,
+    D3D10_SB_RETURN_TYPE_MIXED = 6,
+    D3D11_SB_RETURN_TYPE_DOUBLE = 7,
+    D3D11_SB_RETURN_TYPE_CONTINUED = 8,
+    D3D11_SB_RETURN_TYPE_UNUSED = 9,
+} D3D10_SB_RESOURCE_RETURN_TYPE;
+
+typedef enum D3D10_SB_REGISTER_COMPONENT_TYPE
+{
+    D3D10_SB_REGISTER_COMPONENT_UNKNOWN = 0,
+    D3D10_SB_REGISTER_COMPONENT_UINT32 = 1,
+    D3D10_SB_REGISTER_COMPONENT_SINT32 = 2,
+    D3D10_SB_REGISTER_COMPONENT_FLOAT32 = 3
+} D3D10_SB_REGISTER_COMPONENT_TYPE;
+
+typedef enum D3D10_SB_INSTRUCTION_RETURN_TYPE
+{
+    D3D10_SB_INSTRUCTION_RETURN_FLOAT      = 0,
+    D3D10_SB_INSTRUCTION_RETURN_UINT       = 1
+} D3D10_SB_INSTRUCTION_RETURN_TYPE;
+
+#define D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK  0x00001800
+#define D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT 11
+
+// DECODER MACRO: For an OpcodeToken0 with the return type 
+// determine the return type.
+#define DECODE_D3D10_SB_INSTRUCTION_RETURN_TYPE(OpcodeToken0) ((D3D10_SB_INSTRUCTION_RETURN_TYPE)(((OpcodeToken0)&D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK)>>D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT))
+// ENCODER MACRO: Encode the return type for instructions
+// in the opcode specific control range of OpcodeToken0
+#define ENCODE_D3D10_SB_INSTRUCTION_RETURN_TYPE(ReturnType) (((ReturnType)<<D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT)&D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK)
+
+// ----------------------------------------------------------------------------
+// Interface function body Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_FUNCTION_BODY
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  If it is extended, then
+//         it contains the actual instruction length in DWORDs, since
+//         it may not fit into 7 bits if enough operands are defined.
+//
+// OpcodeToken0 is followed by a DWORD that represents the function body
+// identifier.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Interface function table Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_FUNCTION_TABLE
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  If it is extended, then
+//         it contains the actual instruction length in DWORDs, since
+//         it may not fit into 7 bits if enough functions are defined.
+//
+// OpcodeToken0 is followed by a DWORD that represents the function table
+// identifier and another DWORD (TableLength) that gives the number of
+// functions in the table.
+//
+// This is followed by TableLength DWORDs which are function body indices.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Interface Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_DCL_INTERFACE
+// [11]    1 if the interface is indexed dynamically, 0 otherwise.
+// [23:12] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  If it is extended, then
+//         it contains the actual instruction length in DWORDs, since
+//         it may not fit into 7 bits if enough types are used.
+//
+// OpcodeToken0 is followed by a DWORD that represents the interface
+// identifier. Next is a DWORD that gives the expected function table
+// length. Then another DWORD (OpcodeToken3) with the following layout:
+//
+// [15:00] TableLength, the number of types that implement this interface
+// [31:16] ArrayLength, the number of interfaces that are defined in this array.
+//
+// This is followed by TableLength DWORDs which are function table
+// identifiers, representing possible tables for a given interface.
+//
+// ----------------------------------------------------------------------------
+
+#define D3D11_SB_INTERFACE_INDEXED_BIT_MASK  0x00000800
+#define D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT 11
+
+#define D3D11_SB_INTERFACE_TABLE_LENGTH_MASK  0x0000ffff
+#define D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT 0
+
+#define D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK  0xffff0000
+#define D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT 16
+
+// get/set the indexed bit for an interface definition
+#define DECODE_D3D11_SB_INTERFACE_INDEXED_BIT(OpcodeToken0) ((((OpcodeToken0)&D3D11_SB_INTERFACE_INDEXED_BIT_MASK)>>D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT) ? true : false)
+#define ENCODE_D3D11_SB_INTERFACE_INDEXED_BIT(IndexedBit) (((IndexedBit)<<D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT)&D3D11_SB_INTERFACE_INDEXED_BIT_MASK)
+
+// get/set the table length for an interface definition
+#define DECODE_D3D11_SB_INTERFACE_TABLE_LENGTH(OpcodeToken0) ((UINT)(((OpcodeToken0)&D3D11_SB_INTERFACE_TABLE_LENGTH_MASK)>>D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT))
+#define ENCODE_D3D11_SB_INTERFACE_TABLE_LENGTH(TableLength) (((TableLength)<<D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT)&D3D11_SB_INTERFACE_TABLE_LENGTH_MASK)
+
+// get/set the array length for an interface definition
+#define DECODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(OpcodeToken0) ((UINT)(((OpcodeToken0)&D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK)>>D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT))
+#define ENCODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(ArrayLength) (((ArrayLength)<<D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT)&D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK)
+
+// ----------------------------------------------------------------------------
+// Interface call
+//
+// OpcodeToken0:
+//
+// [10:00] D3D10_SB_OPCODE_INTERFACE_CALL
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  If it is extended, then
+//         it contains the actual instruction length in DWORDs, since
+//         it may not fit into 7 bits if enough types are used.
+//
+// OpcodeToken0 is followed by a DWORD that gives the function index to
+// call in the function table specified for the given interface. 
+// Next is the interface operand.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Thread Group Declaration (Compute Shader)
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_THREAD_GROUP
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  If it is extended, then
+//         it contains the actual instruction length in DWORDs, since
+//         it may not fit into 7 bits if enough types are used.
+//
+// OpcodeToken0 is followed by 3 DWORDs, the Thread Group dimensions as UINT32:
+// x, y, z
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Typed Unordered Access View Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED
+// [15:11] D3D10_SB_RESOURCE_DIMENSION
+// [16:16] D3D11_SB_GLOBALLY_COHERENT_ACCESS or 0 (LOCALLY_COHERENT)
+// [17:17] D3D11_SB_RASTERIZER_ORDERED_ACCESS or 0
+// [23:18] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Models 4.0 through 5.0:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is being declared.
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+//
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (u<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of UAV's in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the u# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (u<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of uav within space (may be dynamically indexed)
+// (2) a Resource Return Type token (ResourceReturnTypeToken)
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+// UAV access scope flags
+#define D3D11_SB_GLOBALLY_COHERENT_ACCESS 0x00010000
+#define D3D11_SB_ACCESS_COHERENCY_MASK    0x00010000
+
+// DECODER MACRO: Retrieve flags for sync instruction from OpcodeToken0.
+#define DECODE_D3D11_SB_ACCESS_COHERENCY_FLAGS(OperandToken0) ((OperandToken0)&D3D11_SB_ACCESS_COHERENCY_MASK)
+
+// ENCODER MACRO: Given a set of sync instruciton flags, encode them in OpcodeToken0.
+#define ENCODE_D3D11_SB_ACCESS_COHERENCY_FLAGS(Flags) ((Flags)&D3D11_SB_ACCESS_COHERENCY_MASK)
+
+// Additional UAV access flags
+#define D3D11_SB_RASTERIZER_ORDERED_ACCESS 0x00020000
+
+// Resource flags mask.  Use to retrieve all resource flags, including the order preserving counter.
+#define D3D11_SB_RESOURCE_FLAGS_MASK    (D3D11_SB_GLOBALLY_COHERENT_ACCESS|D3D11_SB_RASTERIZER_ORDERED_ACCESS|D3D11_SB_UAV_HAS_ORDER_PRESERVING_COUNTER)
+
+// DECODER MACRO: Retrieve UAV access flags for from OpcodeToken0.
+#define DECODE_D3D11_SB_RESOURCE_FLAGS(OperandToken0) ((OperandToken0)&D3D11_SB_RESOURCE_FLAGS_MASK)
+
+// ENCODER MACRO: Given UAV access flags, encode them in OpcodeToken0.
+#define ENCODE_D3D11_SB_RESOURCE_FLAGS(Flags) ((Flags)&D3D11_SB_RESOURCE_FLAGS_MASK)
+
+// ----------------------------------------------------------------------------
+// Raw Unordered Access View Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW
+// [15:11] Ignored, 0
+// [16:16] D3D11_SB_GLOBALLY_COHERENT_ACCESS or 0 (LOCALLY_COHERENT)
+// [17:17] D3D11_SB_RASTERIZER_ORDERED_ACCESS or 0
+// [23:18] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand on Shader Models 4.0 through 5.0:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is being declared.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (u<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of UAV's in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the u# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (u<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of uav within space (may be dynamically indexed)
+// (2) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Structured Unordered Access View Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED
+// [15:11] Ignored, 0
+// [16:16] D3D11_SB_GLOBALLY_COHERENT_ACCESS or 0 (LOCALLY_COHERENT)
+// [17:17] D3D11_SB_RASTERIZER_ORDERED_ACCESS or 0
+// [22:18] Ignored, 0
+// [23:23] D3D11_SB_UAV_HAS_ORDER_PRESERVING_COUNTER or 0
+//
+//            The presence of this flag means that if a UAV is bound to the
+//            corresponding slot, it must have been created with 
+//            D3D11_BUFFER_UAV_FLAG_COUNTER at the API.  Also, the shader
+//            can contain either imm_atomic_alloc or _consume instructions
+//            operating on the given UAV.
+// 
+//            If this flag is not present, the shader can still contain
+//            either imm_atomic_alloc or imm_atomic_consume instructions for
+//            this UAV.  But if such instructions are present in this case,
+//            and a UAV is bound corresponding slot, it must have been created 
+//            with the D3D11_BUFFER_UAV_FLAG_APPEND flag at the API.
+//            Append buffers have a counter as well, but values returned 
+//            to the shader are only valid for the lifetime of the shader 
+//            invocation.
+//
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is 
+//     being declared.
+// (2) a DWORD indicating UINT32 byte stride
+//
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     u# register (D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (u<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of UAV's in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the u# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (u<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of uav within space (may be dynamically indexed)
+// (2) a DWORD indicating UINT32 byte stride
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+// UAV flags
+#define D3D11_SB_UAV_HAS_ORDER_PRESERVING_COUNTER 0x00800000
+#define D3D11_SB_UAV_FLAGS_MASK                   0x00800000
+
+// DECODER MACRO: Retrieve flags about UAV from OpcodeToken0.
+#define DECODE_D3D11_SB_UAV_FLAGS(OperandToken0) ((OperandToken0)&D3D11_SB_UAV_FLAGS_MASK)
+
+// ENCODER MACRO: Given a set of UAV flags, encode them in OpcodeToken0.
+#define ENCODE_D3D11_SB_UAV_FLAGS(Flags) ((Flags)&D3D11_SB_UAV_FLAGS_MASK)
+
+// ----------------------------------------------------------------------------
+// Raw Thread Group Shared Memory Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     g# register (D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY) is being declared.
+// (2) a DWORD indicating the byte count, which must be a multiple of 4.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Structured Thread Group Shared Memory Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 3 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     g# register (D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY) is 
+//     being declared.
+// (2) a DWORD indicating UINT32 struct byte stride
+// (3) a DWORD indicating UINT32 struct count
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Raw Shader Resource View Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_RESOURCE_RAW
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 1 operand:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+//
+// OpcodeToken0 is followed by 2 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (t<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of resources in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the t# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (t<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of resource within space (may be dynamically indexed)
+// (2) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Structured Shader Resource View Declaration
+//
+// OpcodeToken0:
+//
+// [10:00] D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED
+// [23:11] Ignored, 0
+// [30:24] Instruction length in DWORDs including the opcode token.
+// [31]    0 normally. 1 if extended operand definition, meaning next DWORD
+//         contains extended operand description.  This dcl is currently not
+//         extended.
+//
+// OpcodeToken0 is followed by 2 operands:
+// (1) an operand, starting with OperandToken0, defining which
+//     g# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is 
+//     being declared.
+// (2) a DWORD indicating UINT32 struct byte stride
+//
+// OpcodeToken0 is followed by 3 operands on Shader Model 5.1 and later:
+// (1) an operand, starting with OperandToken0, defining which
+//     t# register (D3D10_SB_OPERAND_TYPE_RESOURCE) is being declared.
+//     The indexing dimension for the register must be D3D10_SB_OPERAND_INDEX_DIMENSION_3D, 
+//     and the meaning of the index dimensions are as follows: (t<id>[<lbound>:<ubound>])
+//       1 <id>:     variable ID being declared
+//       2 <lbound>: the lower bound of the range of resources in the space
+//       3 <ubound>: the upper bound (inclusive) of this range
+//     As opposed to when the t# is used in shader instructions, where the register
+//     must be D3D10_SB_OPERAND_INDEX_DIMENSION_2D, and the meaning of the index 
+//     dimensions are as follows: (t<id>[<idx>]):
+//       1 <id>:  variable ID being used (matches dcl)
+//       2 <idx>: absolute index of resource within space (may be dynamically indexed)
+// (2) a DWORD indicating UINT32 struct byte stride
+// (3) a DWORD indicating the space index.
+//
+// ----------------------------------------------------------------------------
+
+#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_GAMES) */
+#pragma endregion

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2944 - 142
thirdparty/directx_headers/include/directx/d3d12.h


+ 0 - 0
thirdparty/directx_headers/d3d12compatibility.h → thirdparty/directx_headers/include/directx/d3d12compatibility.h


+ 134 - 15
thirdparty/directx_headers/d3d12sdklayers.h → thirdparty/directx_headers/include/directx/d3d12sdklayers.h

@@ -171,6 +171,13 @@ typedef interface ID3D12SharingContract ID3D12SharingContract;
 #endif 	/* __ID3D12SharingContract_FWD_DEFINED__ */
 
 
+#ifndef __ID3D12ManualWriteTrackingResource_FWD_DEFINED__
+#define __ID3D12ManualWriteTrackingResource_FWD_DEFINED__
+typedef interface ID3D12ManualWriteTrackingResource ID3D12ManualWriteTrackingResource;
+
+#endif 	/* __ID3D12ManualWriteTrackingResource_FWD_DEFINED__ */
+
+
 #ifndef __ID3D12InfoQueue_FWD_DEFINED__
 #define __ID3D12InfoQueue_FWD_DEFINED__
 typedef interface ID3D12InfoQueue ID3D12InfoQueue;
@@ -2237,7 +2244,92 @@ EXTERN_C const IID IID_ID3D12SharingContract;
 #endif 	/* __ID3D12SharingContract_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_d3d12sdklayers_0000_0017 */
+#ifndef __ID3D12ManualWriteTrackingResource_INTERFACE_DEFINED__
+#define __ID3D12ManualWriteTrackingResource_INTERFACE_DEFINED__
+
+/* interface ID3D12ManualWriteTrackingResource */
+/* [unique][local][object][uuid] */ 
+
+
+EXTERN_C const IID IID_ID3D12ManualWriteTrackingResource;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("86ca3b85-49ad-4b6e-aed5-eddb18540f41")
+    ID3D12ManualWriteTrackingResource : public IUnknown
+    {
+    public:
+        virtual void STDMETHODCALLTYPE TrackWrite( 
+            UINT Subresource,
+            _In_opt_  const D3D12_RANGE *pWrittenRange) = 0;
+        
+    };
+    
+    
+#else 	/* C style interface */
+
+    typedef struct ID3D12ManualWriteTrackingResourceVtbl
+    {
+        BEGIN_INTERFACE
+        
+        DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            ID3D12ManualWriteTrackingResource * This,
+            REFIID riid,
+            _COM_Outptr_  void **ppvObject);
+        
+        DECLSPEC_XFGVIRT(IUnknown, AddRef)
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            ID3D12ManualWriteTrackingResource * This);
+        
+        DECLSPEC_XFGVIRT(IUnknown, Release)
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            ID3D12ManualWriteTrackingResource * This);
+        
+        DECLSPEC_XFGVIRT(ID3D12ManualWriteTrackingResource, TrackWrite)
+        void ( STDMETHODCALLTYPE *TrackWrite )( 
+            ID3D12ManualWriteTrackingResource * This,
+            UINT Subresource,
+            _In_opt_  const D3D12_RANGE *pWrittenRange);
+        
+        END_INTERFACE
+    } ID3D12ManualWriteTrackingResourceVtbl;
+
+    interface ID3D12ManualWriteTrackingResource
+    {
+        CONST_VTBL struct ID3D12ManualWriteTrackingResourceVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define ID3D12ManualWriteTrackingResource_QueryInterface(This,riid,ppvObject)	\
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 
+
+#define ID3D12ManualWriteTrackingResource_AddRef(This)	\
+    ( (This)->lpVtbl -> AddRef(This) ) 
+
+#define ID3D12ManualWriteTrackingResource_Release(This)	\
+    ( (This)->lpVtbl -> Release(This) ) 
+
+
+#define ID3D12ManualWriteTrackingResource_TrackWrite(This,Subresource,pWrittenRange)	\
+    ( (This)->lpVtbl -> TrackWrite(This,Subresource,pWrittenRange) ) 
+
+#endif /* COBJMACROS */
+
+
+#endif 	/* C style interface */
+
+
+
+
+#endif 	/* __ID3D12ManualWriteTrackingResource_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_d3d12sdklayers_0000_0018 */
 /* [local] */ 
 
 typedef 
@@ -2375,6 +2467,9 @@ enum D3D12_MESSAGE_ID
         D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLENDALPHA	= 115,
         D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOPALPHA	= 116,
         D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDRENDERTARGETWRITEMASK	= 117,
+        D3D12_MESSAGE_ID_GET_PROGRAM_IDENTIFIER_ERROR	= 118,
+        D3D12_MESSAGE_ID_GET_WORK_GRAPH_PROPERTIES_ERROR	= 119,
+        D3D12_MESSAGE_ID_SET_PROGRAM_ERROR	= 120,
         D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_INVALID	= 135,
         D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_ROOT_SIGNATURE_NOT_SET	= 200,
         D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_ROOT_SIGNATURE_MISMATCH	= 201,
@@ -3176,8 +3271,6 @@ enum D3D12_MESSAGE_ID
         D3D12_MESSAGE_ID_UNSUPPORTED_BARRIER_LAYOUT	= 1341,
         D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_INVALID_PARAMETERS	= 1342,
         D3D12_MESSAGE_ID_ENHANCED_BARRIERS_NOT_SUPPORTED	= 1343,
-        D3D12_MESSAGE_ID_CAST_TARGET_TEXEL_SIZE_MISMATCH	= 1344,
-        D3D12_MESSAGE_ID_CAST_TO_PLANAR_NOT_SUPORTED	= 1345,
         D3D12_MESSAGE_ID_LEGACY_BARRIER_VALIDATION_FORCED_ON	= 1346,
         D3D12_MESSAGE_ID_EMPTY_ROOT_DESCRIPTOR_TABLE	= 1347,
         D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_ELEMENT_OFFSET_UNALIGNED	= 1348,
@@ -3191,10 +3284,35 @@ enum D3D12_MESSAGE_ID
         D3D12_MESSAGE_ID_NON_OPTIMAL_BARRIER_ONLY_EXECUTE_COMMAND_LISTS	= 1356,
         D3D12_MESSAGE_ID_EXECUTE_INDIRECT_ZERO_COMMAND_COUNT	= 1357,
         D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_INCOMPATIBLE_TEXTURE_LAYOUT	= 1358,
-        D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DYNAMIC_INDEX_BUFFER_STRIP_CUT_NOT_SUPPORTED	= 1359,
+        D3D12_MESSAGE_ID_DYNAMIC_INDEX_BUFFER_STRIP_CUT_NOT_SUPPORTED	= 1359,
         D3D12_MESSAGE_ID_PRIMITIVE_TOPOLOGY_TRIANGLE_FANS_NOT_SUPPORTED	= 1360,
         D3D12_MESSAGE_ID_CREATE_SAMPLER_COMPARISON_FUNC_IGNORED	= 1361,
-        D3D12_MESSAGE_ID_D3D12_MESSAGES_END	= ( D3D12_MESSAGE_ID_CREATE_SAMPLER_COMPARISON_FUNC_IGNORED + 1 ) 
+        D3D12_MESSAGE_ID_CREATEHEAP_INVALIDHEAPTYPE	= 1362,
+        D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_INVALIDHEAPTYPE	= 1363,
+        D3D12_MESSAGE_ID_DYNAMIC_DEPTH_BIAS_NOT_SUPPORTED	= 1364,
+        D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_NON_WHOLE_DYNAMIC_DEPTH_BIAS	= 1365,
+        D3D12_MESSAGE_ID_DYNAMIC_DEPTH_BIAS_FLAG_MISSING	= 1366,
+        D3D12_MESSAGE_ID_DYNAMIC_DEPTH_BIAS_NO_PIPELINE	= 1367,
+        D3D12_MESSAGE_ID_DYNAMIC_INDEX_BUFFER_STRIP_CUT_FLAG_MISSING	= 1368,
+        D3D12_MESSAGE_ID_DYNAMIC_INDEX_BUFFER_STRIP_CUT_NO_PIPELINE	= 1369,
+        D3D12_MESSAGE_ID_NONNORMALIZED_COORDINATE_SAMPLING_NOT_SUPPORTED	= 1370,
+        D3D12_MESSAGE_ID_INVALID_CAST_TARGET	= 1371,
+        D3D12_MESSAGE_ID_RENDER_PASS_COMMANDLIST_INVALID_END_STATE	= 1372,
+        D3D12_MESSAGE_ID_RENDER_PASS_COMMANDLIST_INVALID_START_STATE	= 1373,
+        D3D12_MESSAGE_ID_RENDER_PASS_MISMATCHING_ACCESS	= 1374,
+        D3D12_MESSAGE_ID_RENDER_PASS_MISMATCHING_LOCAL_PRESERVE_PARAMETERS	= 1375,
+        D3D12_MESSAGE_ID_RENDER_PASS_LOCAL_PRESERVE_RENDER_PARAMETERS_ERROR	= 1376,
+        D3D12_MESSAGE_ID_RENDER_PASS_LOCAL_DEPTH_STENCIL_ERROR	= 1377,
+        D3D12_MESSAGE_ID_DRAW_POTENTIALLY_OUTSIDE_OF_VALID_RENDER_AREA	= 1378,
+        D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALID_LINERASTERIZATIONMODE	= 1379,
+        D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE	= 1380,
+        D3D12_MESSAGE_ID_GENERIC_DEVICE_OPERATION_UNSUPPORTED	= 1381,
+        D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDER_TARGET_WRONG_WRITE_MASK	= 1382,
+        D3D12_MESSAGE_ID_PROBABLE_PIX_EVENT_LEAK	= 1383,
+        D3D12_MESSAGE_ID_PIX_EVENT_UNDERFLOW	= 1384,
+        D3D12_MESSAGE_ID_RECREATEAT_INVALID_TARGET	= 1385,
+        D3D12_MESSAGE_ID_RECREATEAT_INSUFFICIENT_SUPPORT	= 1386,
+        D3D12_MESSAGE_ID_D3D12_MESSAGES_END	= ( D3D12_MESSAGE_ID_RECREATEAT_INSUFFICIENT_SUPPORT + 1 ) 
     } 	D3D12_MESSAGE_ID;
 
 typedef struct D3D12_MESSAGE
@@ -3225,8 +3343,8 @@ typedef struct D3D12_INFO_QUEUE_FILTER
 #define D3D12_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT 1024
 
 
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0017_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0017_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0018_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0018_v0_0_s_ifspec;
 
 #ifndef __ID3D12InfoQueue_INTERFACE_DEFINED__
 #define __ID3D12InfoQueue_INTERFACE_DEFINED__
@@ -3671,7 +3789,7 @@ EXTERN_C const IID IID_ID3D12InfoQueue;
 #endif 	/* __ID3D12InfoQueue_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_d3d12sdklayers_0000_0018 */
+/* interface __MIDL_itf_d3d12sdklayers_0000_0019 */
 /* [local] */ 
 
 typedef 
@@ -3691,8 +3809,8 @@ typedef void ( __stdcall *D3D12MessageFunc )(
 
 
 
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0018_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0018_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0019_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0019_v0_0_s_ifspec;
 
 #ifndef __ID3D12InfoQueue1_INTERFACE_DEFINED__
 #define __ID3D12InfoQueue1_INTERFACE_DEFINED__
@@ -3712,7 +3830,7 @@ EXTERN_C const IID IID_ID3D12InfoQueue1;
         virtual HRESULT STDMETHODCALLTYPE RegisterMessageCallback( 
             _In_  D3D12MessageFunc CallbackFunc,
             _In_  D3D12_MESSAGE_CALLBACK_FLAGS CallbackFilterFlags,
-            _In_  void *pContext,
+            _Inout_  void *pContext,
             _Inout_  DWORD *pCallbackCookie) = 0;
         
         virtual HRESULT STDMETHODCALLTYPE UnregisterMessageCallback( 
@@ -3914,7 +4032,7 @@ EXTERN_C const IID IID_ID3D12InfoQueue1;
             ID3D12InfoQueue1 * This,
             _In_  D3D12MessageFunc CallbackFunc,
             _In_  D3D12_MESSAGE_CALLBACK_FLAGS CallbackFilterFlags,
-            _In_  void *pContext,
+            _Inout_  void *pContext,
             _Inout_  DWORD *pCallbackCookie);
         
         DECLSPEC_XFGVIRT(ID3D12InfoQueue1, UnregisterMessageCallback)
@@ -4068,7 +4186,7 @@ EXTERN_C const IID IID_ID3D12InfoQueue1;
 #endif 	/* __ID3D12InfoQueue1_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_d3d12sdklayers_0000_0019 */
+/* interface __MIDL_itf_d3d12sdklayers_0000_0020 */
 /* [local] */ 
 
 #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_GAMES) */
@@ -4090,12 +4208,13 @@ DEFINE_GUID(IID_ID3D12DebugCommandList,0x09e0bf36,0x54ac,0x484f,0x88,0x47,0x4b,0
 DEFINE_GUID(IID_ID3D12DebugCommandList2,0xaeb575cf,0x4e06,0x48be,0xba,0x3b,0xc4,0x50,0xfc,0x96,0x65,0x2e);
 DEFINE_GUID(IID_ID3D12DebugCommandList3,0x197d5e15,0x4d37,0x4d34,0xaf,0x78,0x72,0x4c,0xd7,0x0f,0xdb,0x1f);
 DEFINE_GUID(IID_ID3D12SharingContract,0x0adf7d52,0x929c,0x4e61,0xad,0xdb,0xff,0xed,0x30,0xde,0x66,0xef);
+DEFINE_GUID(IID_ID3D12ManualWriteTrackingResource,0x86ca3b85,0x49ad,0x4b6e,0xae,0xd5,0xed,0xdb,0x18,0x54,0x0f,0x41);
 DEFINE_GUID(IID_ID3D12InfoQueue,0x0742a90b,0xc387,0x483f,0xb9,0x46,0x30,0xa7,0xe4,0xe6,0x14,0x58);
 DEFINE_GUID(IID_ID3D12InfoQueue1,0x2852dd88,0xb484,0x4c0c,0xb6,0xb1,0x67,0x16,0x85,0x00,0xe6,0x00);
 
 
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0019_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0019_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0020_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12sdklayers_0000_0020_v0_0_s_ifspec;
 
 /* Additional Prototypes for ALL interfaces */
 

+ 0 - 0
thirdparty/directx_headers/d3d12shader.h → thirdparty/directx_headers/include/directx/d3d12shader.h


+ 645 - 28
thirdparty/directx_headers/d3d12video.h → thirdparty/directx_headers/include/directx/d3d12video.h

@@ -338,7 +338,9 @@ enum D3D12_FEATURE_VIDEO
         D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT	= 42,
         D3D12_FEATURE_VIDEO_ENCODER_SUPPORT	= 43,
         D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT	= 44,
-        D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS	= 45
+        D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS	= 45,
+        D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG	= 46,
+        D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1	= 47
     } 	D3D12_FEATURE_VIDEO;
 
 typedef 
@@ -6311,6 +6313,16 @@ DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_SIMPLE, 0xefd64d74, 0xc9e8,0x41d
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_ADVSIMPLE_NOGMC, 0xed418a9f, 0x010d, 0x4eda, 0x9a, 0xe3, 0x9a, 0x65, 0x35, 0x8d, 0x8d, 0x2e);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN, 0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10, 0x107af0e0, 0xef1a, 0x4d19, 0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MONOCHROME, 0x0685b993, 0x3d8c, 0x43a0, 0x8b, 0x28, 0xd7, 0x4c, 0x2d, 0x68, 0x99, 0xa4);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MONOCHROME10, 0x142a1d0f, 0x69dd, 0x4ec9, 0x85, 0x91, 0xb1, 0x2f, 0xfc, 0xb9, 0x1a, 0x29);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN12, 0x1a72925f, 0x0c2c, 0x4f15, 0x96, 0xfb, 0xb1, 0x7d, 0x14, 0x73, 0x60, 0x3f);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10_422, 0x0bac4fe5, 0x1532, 0x4429, 0xa8, 0x54, 0xf8, 0x4d, 0xe0, 0x49, 0x53, 0xdb);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN12_422, 0x55bcac81, 0xf311, 0x4093, 0xa7, 0xd0, 0x1c, 0xbc, 0x0b, 0x84, 0x9b, 0xee);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN_444, 0x4008018f, 0xf537, 0x4b36, 0x98, 0xcf, 0x61, 0xaf, 0x8a, 0x2c, 0x1a, 0x33);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10_EXT, 0x9cc55490, 0xe37c, 0x4932, 0x86, 0x84, 0x49, 0x20, 0xf9, 0xf6, 0x40, 0x9c);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10_444, 0x0dabeffa, 0x4458, 0x4602, 0xbc, 0x03, 0x07, 0x95, 0x65, 0x9d, 0x61, 0x7c);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN12_444, 0x9798634d, 0xfe9d, 0x48e5, 0xb4, 0xda, 0xdb, 0xec, 0x45, 0xb3, 0xdf, 0x01);
+DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN16, 0xa4fbdbb0, 0xa113, 0x482b, 0xa2, 0x32, 0x63, 0x5c, 0xc0, 0x69, 0x7f, 0x6d);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_VP9, 0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2, 0xa4c749ef, 0x6ecf, 0x48aa, 0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_VP8, 0x90b899ea, 0x3a62, 0x4705, 0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7);
@@ -6319,6 +6331,463 @@ DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1, 0x6936ff0f, 0x45b1, 0x4163,
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2, 0x0c5f2aa1, 0xe541, 0x4089, 0xbb, 0x7b, 0x98, 0x11, 0x0a, 0x19, 0xd7, 0xc8);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2, 0x17127009, 0xa00f, 0x4ce1, 0x99, 0x4e, 0xbf, 0x40, 0x81, 0xf6, 0xf3, 0xf0);
 DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420, 0x2d80bed6, 0x9cac, 0x4835, 0x9e, 0x91, 0x32, 0x7b, 0xbc, 0x4f, 0x9e, 0xe8);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_PROFILE
+    {
+        D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN	= 0,
+        D3D12_VIDEO_ENCODER_AV1_PROFILE_HIGH	= 1,
+        D3D12_VIDEO_ENCODER_AV1_PROFILE_PROFESSIONAL	= 2
+    } 	D3D12_VIDEO_ENCODER_AV1_PROFILE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_LEVELS
+    {
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_2_0	= 0,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_2_1	= 1,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_2_2	= 2,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_2_3	= 3,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_3_0	= 4,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_3_1	= 5,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_3_2	= 6,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_3_3	= 7,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_4_0	= 8,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_4_1	= 9,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_4_2	= 10,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_4_3	= 11,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_5_0	= 12,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_5_1	= 13,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2	= 14,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_5_3	= 15,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_6_0	= 16,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_6_1	= 17,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_6_2	= 18,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_6_3	= 19,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_7_0	= 20,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_7_1	= 21,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_7_2	= 22,
+        D3D12_VIDEO_ENCODER_AV1_LEVELS_7_3	= 23
+    } 	D3D12_VIDEO_ENCODER_AV1_LEVELS;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_TIER
+    {
+        D3D12_VIDEO_ENCODER_AV1_TIER_MAIN	= 0,
+        D3D12_VIDEO_ENCODER_AV1_TIER_HIGH	= 1
+    } 	D3D12_VIDEO_ENCODER_AV1_TIER;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS
+    {
+    D3D12_VIDEO_ENCODER_AV1_LEVELS Level;
+    D3D12_VIDEO_ENCODER_AV1_TIER Tier;
+    } 	D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK	= 0x1,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA	= 0x2,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER	= 0x4,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND	= 0x8,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND	= 0x10,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION	= 0x20,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER	= 0x40,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP	= 0x80,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS	= 0x100,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION	= 0x200,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER	= 0x400,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING	= 0x800,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING	= 0x1000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY	= 0x2000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS	= 0x4000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS	= 0x8000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION	= 0x10000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION	= 0x20000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS	= 0x40000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS	= 0x80000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX	= 0x100000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET	= 0x200000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE	= 0x400000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV	= 0x800000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SKIP_MODE_PRESENT	= 0x1000000,
+        D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DELTA_LF_PARAMS	= 0x2000000
+    } 	D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_TX_MODE
+    {
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_ONLY4x4	= 0,
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_LARGEST	= 1,
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT	= 2
+    } 	D3D12_VIDEO_ENCODER_AV1_TX_MODE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_ONLY4x4	= ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_ONLY4x4 ) ,
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_LARGEST	= ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_LARGEST ) ,
+        D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_SELECT	= ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT ) 
+    } 	D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS
+    {
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP	= 0,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SMOOTH	= 1,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SHARP	= 2,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_BILINEAR	= 3,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE	= 4
+    } 	D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP	= ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP ) ,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SMOOTH	= ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SMOOTH ) ,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SHARP	= ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SHARP ) ,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_BILINEAR	= ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_BILINEAR ) ,
+        D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_SWITCHABLE	= ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE ) 
+    } 	D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE
+    {
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_4x4	= 0,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_8x8	= 1,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_16x16	= 2,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_32x32	= 3,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_64x64	= 4
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE
+    {
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_DISABLED	= 0,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_Q	= 1,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_V	= 2,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_H	= 3,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_U	= 4,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_V	= 5,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_REF_FRAME	= 6,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_SKIP	= 7,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_GLOBALMV	= 8
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_DISABLED	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_DISABLED ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_Q	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_Q ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_V	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_V ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_H	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_H ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_U	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_U ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_V	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_V ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_REF_FRAME	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_REF_FRAME ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_SKIP	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_SKIP ) ,
+        D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_GLOBALMV	= ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_GLOBALMV ) 
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE
+    {
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED	= 0,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_SWITCHABLE	= 1,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_WIENER	= 2,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_SGRPROJ	= 3
+    } 	D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE
+    {
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_DISABLED	= 0,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_32x32	= 1,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_64x64	= 2,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_128x128	= 3,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_256x256	= 4
+    } 	D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_NOT_SUPPORTED	= 0,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_32x32	= 0x1,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_64x64	= 0x2,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_128x128	= 0x4,
+        D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_256x256	= 0x8
+    } 	D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION
+    {
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_IDENTITY	= 0,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_TRANSLATION	= 1,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_ROTZOOM	= 2,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_AFFINE	= 3
+    } 	D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_IDENTITY	= ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_IDENTITY ) ,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_TRANSLATION	= ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_TRANSLATION ) ,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_ROTZOOM	= ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_ROTZOOM ) ,
+        D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_AFFINE	= ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_AFFINE ) 
+    } 	D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION	= 0x1,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION_DELTA	= 0x2,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER	= 0x4,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER_DELTA	= 0x8,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CDEF_DATA	= 0x10,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CONTEXT_UPDATE_TILE_ID	= 0x20,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_COMPOUND_PREDICTION_MODE	= 0x40,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_PRIMARY_REF_FRAME	= 0x80,
+        D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_REFERENCE_INDICES	= 0x100
+    } 	D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS);
+typedef struct D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT
+    {
+    D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS SupportedFeatureFlags;
+    D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS RequiredFeatureFlags;
+    D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS SupportedInterpolationFilters;
+    D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS SupportedRestorationParams[ 3 ][ 3 ];
+    D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS SupportedSegmentationModes;
+    D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS SupportedTxModes[ 4 ];
+    D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE SegmentationBlockSize;
+    D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS PostEncodeValuesFlags;
+    UINT MaxTemporalLayers;
+    UINT MaxSpatialLayers;
+    } 	D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE
+    {
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME	= 0,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME	= 1,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME	= 2,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME	= 3
+    } 	D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_KEY_FRAME	= ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME ) ,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_INTER_FRAME	= ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME ) ,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_INTRA_ONLY_FRAME	= ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME ) ,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_SWITCH_FRAME	= ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME ) 
+    } 	D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS);
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE
+    {
+        D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_COMPOUND_REFERENCE	= 1
+    } 	D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE;
+
+typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT
+    {
+    D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE PredictionMode;
+    UINT MaxUniqueReferencesPerFrame;
+    D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS SupportedFrameTypes;
+    D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS SupportedReferenceWarpedMotionFlags;
+    } 	D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION
+    {
+    D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS FeatureFlags;
+    UINT OrderHintBitsMinus1;
+    } 	D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE
+    {
+    UINT IntraDistance;
+    UINT InterFramePeriod;
+    } 	D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO
+    {
+    D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION TransformationType;
+    INT TransformationMatrix[ 8 ];
+    BOOL InvalidAffineSet;
+    } 	D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR
+    {
+    UINT ReconstructedPictureResourceIndex;
+    UINT TemporalLayerIndexPlus1;
+    UINT SpatialLayerIndexPlus1;
+    D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE FrameType;
+    D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO WarpedMotionInfo;
+    UINT OrderHint;
+    UINT PictureIndex;
+    } 	D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR;
+
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE	= 0x1,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_CDF_UPDATE	= 0x2,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING	= 0x4,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE	= 0x8,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS	= 0x10,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS	= 0x20,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY	= 0x40,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_USE_SUPER_RESOLUTION	= 0x80,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_FRAME_END_UPDATE_CDF	= 0x100,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO	= 0x200,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_CUSTOM	= 0x400,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION	= 0x800,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET	= 0x1000,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE	= 0x2000,
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV	= 0x4000
+    } 	D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS);
+typedef struct D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG
+    {
+    D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE FrameRestorationType[ 3 ];
+    D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE LoopRestorationPixelSize[ 3 ];
+    } 	D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA
+    {
+    UINT64 EnabledFeatures;
+    INT64 FeatureValue[ 8 ];
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG
+    {
+    UINT64 UpdateMap;
+    UINT64 TemporalUpdate;
+    UINT64 UpdateData;
+    UINT64 NumSegments;
+    D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA SegmentsData[ 8 ];
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP
+    {
+    UINT SegmentsMapByteSize;
+    UINT8 *pSegmentsMap;
+    } 	D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP;
+
+typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG
+    {
+    UINT64 LoopFilterLevel[ 2 ];
+    UINT64 LoopFilterLevelU;
+    UINT64 LoopFilterLevelV;
+    UINT64 LoopFilterSharpnessLevel;
+    UINT64 LoopFilterDeltaEnabled;
+    UINT64 UpdateRefDelta;
+    INT64 RefDeltas[ 8 ];
+    UINT64 UpdateModeDelta;
+    INT64 ModeDeltas[ 2 ];
+    } 	D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG
+    {
+    UINT64 DeltaLFPresent;
+    UINT64 DeltaLFMulti;
+    UINT64 DeltaLFRes;
+    } 	D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG
+    {
+    UINT64 BaseQIndex;
+    INT64 YDCDeltaQ;
+    INT64 UDCDeltaQ;
+    INT64 UACDeltaQ;
+    INT64 VDCDeltaQ;
+    INT64 VACDeltaQ;
+    UINT64 UsingQMatrix;
+    UINT64 QMY;
+    UINT64 QMU;
+    UINT64 QMV;
+    } 	D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG
+    {
+    UINT64 DeltaQPresent;
+    UINT64 DeltaQRes;
+    } 	D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG
+    {
+    UINT64 CdefBits;
+    UINT64 CdefDampingMinus3;
+    UINT64 CdefYPriStrength[ 8 ];
+    UINT64 CdefUVPriStrength[ 8 ];
+    UINT64 CdefYSecStrength[ 8 ];
+    UINT64 CdefUVSecStrength[ 8 ];
+    } 	D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA
+    {
+    D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS Flags;
+    D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE FrameType;
+    D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE CompoundPredictionType;
+    D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS InterpolationFilter;
+    D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG FrameRestorationConfig;
+    D3D12_VIDEO_ENCODER_AV1_TX_MODE TxMode;
+    UINT SuperResDenominator;
+    UINT OrderHint;
+    UINT PictureIndex;
+    UINT TemporalLayerIndexPlus1;
+    UINT SpatialLayerIndexPlus1;
+    D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR ReferenceFramesReconPictureDescriptors[ 8 ];
+    UINT ReferenceIndices[ 7 ];
+    UINT PrimaryRefFrame;
+    UINT RefreshFrameFlags;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG LoopFilter;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG LoopFilterDelta;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG Quantization;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG QuantizationDelta;
+    D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG CDEF;
+    UINT QPMapValuesCount;
+    _Field_size_full_(QPMapValuesCount)  INT16 *pRateControlQPMap;
+    D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG CustomSegmentation;
+    D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP CustomSegmentsMap;
+    } 	D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES
+    {
+    UINT64 RowCount;
+    UINT64 ColCount;
+    UINT64 RowHeights[ 64 ];
+    UINT64 ColWidths[ 64 ];
+    UINT64 ContextUpdateTileId;
+    } 	D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES;
+
+typedef struct D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES
+    {
+    UINT64 CompoundPredictionType;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG LoopFilter;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG LoopFilterDelta;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG Quantization;
+    D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG QuantizationDelta;
+    D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG CDEF;
+    D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG SegmentationConfig;
+    UINT64 PrimaryRefFrame;
+    UINT64 ReferenceIndices[ 7 ];
+    } 	D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES;
+
 typedef 
 enum D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE
     {
@@ -6338,7 +6807,9 @@ enum D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS
         D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE	= 0x4,
         D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_INITIAL_QP	= 0x8,
         D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE	= 0x10,
-        D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES	= 0x20
+        D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES	= 0x20,
+        D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT	= 0x40,
+        D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED	= 0x80
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS;
 
 DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS);
@@ -6349,6 +6820,14 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP
     UINT ConstantQP_InterPredictedFrame_BiDirectionalRef;
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP;
 
+typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1
+    {
+    UINT ConstantQP_FullIntracodedFrame;
+    UINT ConstantQP_InterPredictedFrame_PrevRefOnly;
+    UINT ConstantQP_InterPredictedFrame_BiDirectionalRef;
+    UINT QualityVsSpeed;
+    } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1;
+
 typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR
     {
     UINT InitialQP;
@@ -6360,6 +6839,18 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR
     UINT64 InitialVBVFullness;
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR;
 
+typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1
+    {
+    UINT InitialQP;
+    UINT MinQP;
+    UINT MaxQP;
+    UINT64 MaxFrameBitSize;
+    UINT64 TargetBitRate;
+    UINT64 VBVCapacity;
+    UINT64 InitialVBVFullness;
+    UINT QualityVsSpeed;
+    } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1;
+
 typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR
     {
     UINT InitialQP;
@@ -6372,6 +6863,19 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR
     UINT64 InitialVBVFullness;
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR;
 
+typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1
+    {
+    UINT InitialQP;
+    UINT MinQP;
+    UINT MaxQP;
+    UINT64 MaxFrameBitSize;
+    UINT64 TargetAvgBitRate;
+    UINT64 PeakBitRate;
+    UINT64 VBVCapacity;
+    UINT64 InitialVBVFullness;
+    UINT QualityVsSpeed;
+    } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1;
+
 typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR
     {
     UINT InitialQP;
@@ -6383,6 +6887,25 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR
     UINT ConstantQualityTarget;
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR;
 
+typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1
+    {
+    UINT InitialQP;
+    UINT MinQP;
+    UINT MaxQP;
+    UINT64 MaxFrameBitSize;
+    UINT64 TargetAvgBitRate;
+    UINT64 PeakBitRate;
+    UINT ConstantQualityTarget;
+    UINT64 VBVCapacity;
+    UINT64 InitialVBVFullness;
+    UINT QualityVsSpeed;
+    } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1;
+
+typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP
+    {
+    UINT QualityVsSpeed;
+    } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP;
+
 typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS
     {
     UINT DataSize;
@@ -6392,6 +6915,11 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS
         const D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *pConfiguration_CBR;
         const D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *pConfiguration_VBR;
         const D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *pConfiguration_QVBR;
+        const D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1 *pConfiguration_CQP1;
+        const D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1 *pConfiguration_CBR1;
+        const D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1 *pConfiguration_VBR1;
+        const D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 *pConfiguration_QVBR1;
+        const D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP *pConfiguration_AbsoluteQPMap;
         } 	;
     } 	D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS;
 
@@ -6407,7 +6935,8 @@ typedef
 enum D3D12_VIDEO_ENCODER_CODEC
     {
         D3D12_VIDEO_ENCODER_CODEC_H264	= 0,
-        D3D12_VIDEO_ENCODER_CODEC_HEVC	= 1
+        D3D12_VIDEO_ENCODER_CODEC_HEVC	= 1,
+        D3D12_VIDEO_ENCODER_CODEC_AV1	= 2
     } 	D3D12_VIDEO_ENCODER_CODEC;
 
 typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC
@@ -6439,6 +6968,7 @@ typedef struct D3D12_VIDEO_ENCODER_PROFILE_DESC
         {
         D3D12_VIDEO_ENCODER_PROFILE_H264 *pH264Profile;
         D3D12_VIDEO_ENCODER_PROFILE_HEVC *pHEVCProfile;
+        D3D12_VIDEO_ENCODER_AV1_PROFILE *pAV1Profile;
         } 	;
     } 	D3D12_VIDEO_ENCODER_PROFILE_DESC;
 
@@ -6505,6 +7035,7 @@ typedef struct D3D12_VIDEO_ENCODER_LEVEL_SETTING
         {
         D3D12_VIDEO_ENCODER_LEVELS_H264 *pH264LevelSetting;
         D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC *pHEVCLevelSetting;
+        D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS *pAV1LevelSetting;
         } 	;
     } 	D3D12_VIDEO_ENCODER_LEVEL_SETTING;
 
@@ -6591,7 +7122,9 @@ enum D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE
         D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION	= 1,
         D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED	= 2,
         D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION	= 3,
-        D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME	= 4
+        D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME	= 4,
+        D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION	= 5,
+        D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_CONFIGURABLE_GRID_PARTITION	= 6
     } 	D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE;
 
 typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE
@@ -6604,6 +7137,58 @@ typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE
     BOOL IsSupported;
     } 	D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE;
 
+typedef 
+enum D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS
+    {
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_NONE	= 0,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_NOT_SPECIFIED	= 0x1,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_CODEC_CONSTRAINT	= 0x2,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_HARDWARE_CONSTRAINT	= 0x4,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_ROWS_COUNT	= 0x8,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_COLS_COUNT	= 0x10,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_WIDTH	= 0x20,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_AREA	= 0x40,
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_TOTAL_TILES	= 0x80
+    } 	D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS;
+
+DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS);
+typedef struct D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT
+    {
+    BOOL Use128SuperBlocks;
+    D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES TilesConfiguration;
+    D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS ValidationFlags;
+    UINT MinTileRows;
+    UINT MaxTileRows;
+    UINT MinTileCols;
+    UINT MaxTileCols;
+    UINT MinTileWidth;
+    UINT MaxTileWidth;
+    UINT MinTileArea;
+    UINT MaxTileArea;
+    UINT TileSizeBytesMinus1;
+    } 	D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT;
+
+typedef struct D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT
+    {
+    UINT DataSize;
+    union 
+        {
+        D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT *pAV1Support;
+        } 	;
+    } 	D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT;
+
+typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG
+    {
+    UINT NodeIndex;
+    D3D12_VIDEO_ENCODER_CODEC Codec;
+    D3D12_VIDEO_ENCODER_PROFILE_DESC Profile;
+    D3D12_VIDEO_ENCODER_LEVEL_SETTING Level;
+    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE SubregionMode;
+    D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC FrameResolution;
+    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT CodecSupport;
+    BOOL IsSupported;
+    } 	D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG;
+
 typedef 
 enum D3D12_VIDEO_ENCODER_HEAP_FLAGS
     {
@@ -6728,6 +7313,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT
         {
         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 *pH264Support;
         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC *pHEVCSupport;
+        D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT *pAV1Support;
         } 	;
     } 	D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT;
 
@@ -6765,6 +7351,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT
         {
         D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 *pH264Support;
         D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC *pHEVCSupport;
+        D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT *pAV1Support;
         } 	;
     } 	D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT;
 
@@ -6793,7 +7380,9 @@ enum D3D12_VIDEO_ENCODER_SUPPORT_FLAGS
         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_INITIAL_QP_AVAILABLE	= 0x200,
         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE	= 0x400,
         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE	= 0x800,
-        D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE	= 0x1000
+        D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE	= 0x1000,
+        D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_EXTENSION1_SUPPORT	= 0x2000,
+        D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_QUALITY_VS_SPEED_AVAILABLE	= 0x4000
     } 	D3D12_VIDEO_ENCODER_SUPPORT_FLAGS;
 
 DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_SUPPORT_FLAGS);
@@ -6855,6 +7444,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION
         {
         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 *pH264Config;
         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC *pHEVCConfig;
+        D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION *pAV1Config;
         } 	;
     } 	D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION;
 
@@ -6870,7 +7460,8 @@ enum D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
         D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM	= 0,
         D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_FULL_PIXEL	= 1,
         D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_HALF_PIXEL	= 2,
-        D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL	= 3
+        D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL	= 3,
+        D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_EIGHTH_PIXEL	= 4
     } 	D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE;
 
 typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS
@@ -6893,7 +7484,8 @@ enum D3D12_VIDEO_ENCODER_VALIDATION_FLAGS
         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED	= 0x80,
         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED	= 0x100,
         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST	= 0x200,
-        D3D12_VIDEO_ENCODER_VALIDATION_FLAG_GOP_STRUCTURE_NOT_SUPPORTED	= 0x800
+        D3D12_VIDEO_ENCODER_VALIDATION_FLAG_GOP_STRUCTURE_NOT_SUPPORTED	= 0x800,
+        D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_DATA_NOT_SUPPORTED	= 0x1000
     } 	D3D12_VIDEO_ENCODER_VALIDATION_FLAGS;
 
 DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_VALIDATION_FLAGS);
@@ -6920,6 +7512,7 @@ typedef struct D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE
         {
         D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 *pH264GroupOfPictures;
         D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC *pHEVCGroupOfPictures;
+        D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE *pAV1SequenceStructure;
         } 	;
     } 	D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE;
 
@@ -6943,6 +7536,50 @@ typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT
     _Field_size_full_(ResolutionsListCount)  D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS *pResolutionDependentSupport;
     } 	D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT;
 
+typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES
+    {
+    union 
+        {
+        UINT MaxBytesPerSlice;
+        UINT NumberOfCodingUnitsPerSlice;
+        UINT NumberOfRowsPerSlice;
+        UINT NumberOfSlicesPerFrame;
+        } 	;
+    } 	D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES;
+
+typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA
+    {
+    UINT DataSize;
+    union 
+        {
+        const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_H264;
+        const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_HEVC;
+        const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *pTilesPartition_AV1;
+        } 	;
+    } 	D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA;
+
+typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1
+    {
+    UINT NodeIndex;
+    D3D12_VIDEO_ENCODER_CODEC Codec;
+    DXGI_FORMAT InputFormat;
+    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration;
+    D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE CodecGopSequence;
+    D3D12_VIDEO_ENCODER_RATE_CONTROL RateControl;
+    D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE IntraRefresh;
+    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE SubregionFrameEncoding;
+    UINT ResolutionsListCount;
+    const D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC *pResolutionList;
+    UINT MaxReferenceFramesInDPB;
+    D3D12_VIDEO_ENCODER_VALIDATION_FLAGS ValidationFlags;
+    D3D12_VIDEO_ENCODER_SUPPORT_FLAGS SupportFlags;
+    D3D12_VIDEO_ENCODER_PROFILE_DESC SuggestedProfile;
+    D3D12_VIDEO_ENCODER_LEVEL_SETTING SuggestedLevel;
+    _Field_size_full_(ResolutionsListCount)  D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS *pResolutionDependentSupport;
+    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA SubregionFrameEncodingData;
+    UINT MaxQualityVsSpeed;
+    } 	D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1;
+
 typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS
     {
     UINT NodeIndex;
@@ -7716,6 +8353,7 @@ typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA
         {
         D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 *pH264PicData;
         D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC *pHEVCPicData;
+        D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA *pAV1PicData;
         } 	;
     } 	D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA;
 
@@ -7754,27 +8392,6 @@ enum D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS
     } 	D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS;
 
 DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS);
-typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES
-    {
-    union 
-        {
-        UINT MaxBytesPerSlice;
-        UINT NumberOfCodingUnitsPerSlice;
-        UINT NumberOfRowsPerSlice;
-        UINT NumberOfSlicesPerFrame;
-        } 	;
-    } 	D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES;
-
-typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA
-    {
-    UINT DataSize;
-    union 
-        {
-        const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_H264;
-        const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_HEVC;
-        } 	;
-    } 	D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA;
-
 typedef struct D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC
     {
     D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS Flags;

+ 1 - 0
thirdparty/directx_headers/d3dcommon.h → thirdparty/directx_headers/include/directx/d3dcommon.h

@@ -93,6 +93,7 @@ enum D3D_DRIVER_TYPE
 typedef 
 enum D3D_FEATURE_LEVEL
     {
+        D3D_FEATURE_LEVEL_1_0_GENERIC	= 0x100,
         D3D_FEATURE_LEVEL_1_0_CORE	= 0x1000,
         D3D_FEATURE_LEVEL_9_1	= 0x9100,
         D3D_FEATURE_LEVEL_9_2	= 0x9200,

+ 35 - 0
thirdparty/directx_headers/include/directx/d3dx12.h

@@ -0,0 +1,35 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#ifndef __D3DX12_H__
+#define __D3DX12_H__
+
+#include "d3d12.h"
+
+#if defined( __cplusplus )
+
+#include "d3dx12_barriers.h"
+#include "d3dx12_core.h"
+#include "d3dx12_default.h"
+#include "d3dx12_pipeline_state_stream.h"
+#include "d3dx12_render_pass.h"
+#include "d3dx12_resource_helpers.h"
+#include "d3dx12_root_signature.h"
+#include "d3dx12_property_format_table.h"
+
+#ifndef D3DX12_NO_STATE_OBJECT_HELPERS
+#include "d3dx12_state_object.h"
+#endif // !D3DX12_NO_STATE_OBJECT_HELPERS
+
+#ifndef D3DX12_NO_CHECK_FEATURE_SUPPORT_CLASS
+#include "d3dx12_check_feature_support.h"
+#endif // !D3DX12_NO_CHECK_FEATURE_SUPPORT_CLASS
+
+#endif // defined( __cplusplus )
+
+#endif //__D3DX12_H__
+

+ 192 - 0
thirdparty/directx_headers/include/directx/d3dx12_barriers.h

@@ -0,0 +1,192 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#ifndef __D3DX12_BARRIERS_H__
+#define __D3DX12_BARRIERS_H__
+
+#if defined( __cplusplus )
+
+#include "d3d12.h"
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RESOURCE_BARRIER : public D3D12_RESOURCE_BARRIER
+{
+    CD3DX12_RESOURCE_BARRIER() = default;
+    explicit CD3DX12_RESOURCE_BARRIER(const D3D12_RESOURCE_BARRIER &o) noexcept :
+        D3D12_RESOURCE_BARRIER(o)
+    {}
+    static inline CD3DX12_RESOURCE_BARRIER Transition(
+        _In_ ID3D12Resource* pResource,
+        D3D12_RESOURCE_STATES stateBefore,
+        D3D12_RESOURCE_STATES stateAfter,
+        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
+        D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE) noexcept
+    {
+        CD3DX12_RESOURCE_BARRIER result = {};
+        D3D12_RESOURCE_BARRIER &barrier = result;
+        result.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+        result.Flags = flags;
+        barrier.Transition.pResource = pResource;
+        barrier.Transition.StateBefore = stateBefore;
+        barrier.Transition.StateAfter = stateAfter;
+        barrier.Transition.Subresource = subresource;
+        return result;
+    }
+    static inline CD3DX12_RESOURCE_BARRIER Aliasing(
+        _In_opt_ ID3D12Resource* pResourceBefore,
+        _In_opt_ ID3D12Resource* pResourceAfter) noexcept
+    {
+        CD3DX12_RESOURCE_BARRIER result = {};
+        D3D12_RESOURCE_BARRIER &barrier = result;
+        result.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
+        barrier.Aliasing.pResourceBefore = pResourceBefore;
+        barrier.Aliasing.pResourceAfter = pResourceAfter;
+        return result;
+    }
+    static inline CD3DX12_RESOURCE_BARRIER UAV(
+        _In_opt_ ID3D12Resource* pResource) noexcept
+    {
+        CD3DX12_RESOURCE_BARRIER result = {};
+        D3D12_RESOURCE_BARRIER &barrier = result;
+        result.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
+        barrier.UAV.pResource = pResource;
+        return result;
+    }
+};
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+
+//================================================================================================
+// D3DX12 Enhanced Barrier Helpers
+//================================================================================================
+
+class CD3DX12_BARRIER_SUBRESOURCE_RANGE : public D3D12_BARRIER_SUBRESOURCE_RANGE
+{
+public:
+    CD3DX12_BARRIER_SUBRESOURCE_RANGE() = default;
+    CD3DX12_BARRIER_SUBRESOURCE_RANGE(const D3D12_BARRIER_SUBRESOURCE_RANGE &o) noexcept :
+        D3D12_BARRIER_SUBRESOURCE_RANGE(o)
+    {}
+    explicit CD3DX12_BARRIER_SUBRESOURCE_RANGE(UINT Subresource) noexcept :
+        D3D12_BARRIER_SUBRESOURCE_RANGE{ Subresource, 0, 0, 0, 0, 0 }
+    {}
+    CD3DX12_BARRIER_SUBRESOURCE_RANGE(
+        UINT firstMipLevel,
+        UINT numMips,
+        UINT firstArraySlice,
+        UINT numArraySlices,
+        UINT firstPlane = 0,
+        UINT numPlanes = 1) noexcept :
+        D3D12_BARRIER_SUBRESOURCE_RANGE
+        {
+            firstMipLevel,
+            numMips,
+            firstArraySlice,
+            numArraySlices,
+            firstPlane,
+            numPlanes
+        }
+    {}
+};
+
+class CD3DX12_GLOBAL_BARRIER : public D3D12_GLOBAL_BARRIER
+{
+public:
+    CD3DX12_GLOBAL_BARRIER() = default;
+    CD3DX12_GLOBAL_BARRIER(const D3D12_GLOBAL_BARRIER &o) noexcept : D3D12_GLOBAL_BARRIER(o){}
+    CD3DX12_GLOBAL_BARRIER(
+        D3D12_BARRIER_SYNC syncBefore,
+        D3D12_BARRIER_SYNC syncAfter,
+        D3D12_BARRIER_ACCESS accessBefore,
+        D3D12_BARRIER_ACCESS accessAfter) noexcept : D3D12_GLOBAL_BARRIER {
+            syncBefore,
+            syncAfter,
+            accessBefore,
+            accessAfter
+        }
+    {}
+};
+
+class CD3DX12_BUFFER_BARRIER : public D3D12_BUFFER_BARRIER
+{
+public:
+    CD3DX12_BUFFER_BARRIER() = default;
+    CD3DX12_BUFFER_BARRIER(const D3D12_BUFFER_BARRIER &o) noexcept : D3D12_BUFFER_BARRIER(o){}
+    CD3DX12_BUFFER_BARRIER(
+        D3D12_BARRIER_SYNC syncBefore,
+        D3D12_BARRIER_SYNC syncAfter,
+        D3D12_BARRIER_ACCESS accessBefore,
+        D3D12_BARRIER_ACCESS accessAfter,
+        ID3D12Resource *pRes) noexcept : D3D12_BUFFER_BARRIER {
+            syncBefore,
+            syncAfter,
+            accessBefore,
+            accessAfter,
+            pRes,
+            0, ULLONG_MAX
+        }
+    {}
+};
+
+class CD3DX12_TEXTURE_BARRIER : public D3D12_TEXTURE_BARRIER
+{
+public:
+    CD3DX12_TEXTURE_BARRIER() = default;
+    CD3DX12_TEXTURE_BARRIER(const D3D12_TEXTURE_BARRIER &o) noexcept : D3D12_TEXTURE_BARRIER(o){}
+    CD3DX12_TEXTURE_BARRIER(
+        D3D12_BARRIER_SYNC syncBefore,
+        D3D12_BARRIER_SYNC syncAfter,
+        D3D12_BARRIER_ACCESS accessBefore,
+        D3D12_BARRIER_ACCESS accessAfter,
+        D3D12_BARRIER_LAYOUT layoutBefore,
+        D3D12_BARRIER_LAYOUT layoutAfter,
+        ID3D12Resource *pRes,
+        const D3D12_BARRIER_SUBRESOURCE_RANGE &subresources,
+        D3D12_TEXTURE_BARRIER_FLAGS flag = D3D12_TEXTURE_BARRIER_FLAG_NONE) noexcept : D3D12_TEXTURE_BARRIER {
+            syncBefore,
+            syncAfter,
+            accessBefore,
+            accessAfter,
+            layoutBefore,
+            layoutAfter,
+            pRes,
+            subresources,
+            flag
+        }
+    {}
+};
+
+class CD3DX12_BARRIER_GROUP : public D3D12_BARRIER_GROUP
+{
+public:
+    CD3DX12_BARRIER_GROUP() = default;
+    CD3DX12_BARRIER_GROUP(const D3D12_BARRIER_GROUP &o) noexcept : D3D12_BARRIER_GROUP(o){}
+    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_BUFFER_BARRIER *pBarriers) noexcept
+    {
+        Type = D3D12_BARRIER_TYPE_BUFFER;
+        NumBarriers = numBarriers;
+        pBufferBarriers = pBarriers;
+    }
+    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_TEXTURE_BARRIER *pBarriers) noexcept
+    {
+        Type = D3D12_BARRIER_TYPE_TEXTURE;
+        NumBarriers = numBarriers;
+        pTextureBarriers = pBarriers;
+    }
+    CD3DX12_BARRIER_GROUP(UINT32 numBarriers, const D3D12_GLOBAL_BARRIER *pBarriers) noexcept
+    {
+        Type = D3D12_BARRIER_TYPE_GLOBAL;
+        NumBarriers = numBarriers;
+        pGlobalBarriers = pBarriers;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 608
+
+
+#endif // defined( __cplusplus )
+
+#endif // __D3DX12_BARRIERS_H__

+ 1107 - 0
thirdparty/directx_headers/include/directx/d3dx12_check_feature_support.h

@@ -0,0 +1,1107 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+
+//================================================================================================
+// D3DX12 Check Feature Support
+//================================================================================================
+
+#include <vector>
+
+class CD3DX12FeatureSupport
+{
+public: // Function declaration
+    // Default constructor that creates an empty object
+    CD3DX12FeatureSupport() noexcept;
+
+    // Initialize data from the given device
+    HRESULT Init(ID3D12Device* pDevice);
+
+    // Retreives the status of the object. If an error occurred in the initialization process, the function returns the error code.
+    HRESULT GetStatus() const noexcept { return m_hStatus; }
+
+    // Getter functions for each feature class
+    // D3D12_OPTIONS
+    BOOL DoublePrecisionFloatShaderOps() const noexcept;
+    BOOL OutputMergerLogicOp() const noexcept;
+    D3D12_SHADER_MIN_PRECISION_SUPPORT MinPrecisionSupport() const noexcept;
+    D3D12_TILED_RESOURCES_TIER TiledResourcesTier() const noexcept;
+    D3D12_RESOURCE_BINDING_TIER ResourceBindingTier() const noexcept;
+    BOOL PSSpecifiedStencilRefSupported() const noexcept;
+    BOOL TypedUAVLoadAdditionalFormats() const noexcept;
+    BOOL ROVsSupported() const noexcept;
+    D3D12_CONSERVATIVE_RASTERIZATION_TIER ConservativeRasterizationTier() const noexcept;
+    BOOL StandardSwizzle64KBSupported() const noexcept;
+    BOOL CrossAdapterRowMajorTextureSupported() const noexcept;
+    BOOL VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation() const noexcept;
+    D3D12_RESOURCE_HEAP_TIER ResourceHeapTier() const noexcept;
+    D3D12_CROSS_NODE_SHARING_TIER CrossNodeSharingTier() const noexcept;
+    UINT MaxGPUVirtualAddressBitsPerResource() const noexcept;
+
+    // FEATURE_LEVELS
+    D3D_FEATURE_LEVEL MaxSupportedFeatureLevel() const noexcept;
+
+    // FORMAT_SUPPORT
+    HRESULT FormatSupport(DXGI_FORMAT Format, D3D12_FORMAT_SUPPORT1& Support1, D3D12_FORMAT_SUPPORT2& Support2) const;
+
+    // MUTLTISAMPLE_QUALITY_LEVELS
+    HRESULT MultisampleQualityLevels(DXGI_FORMAT Format, UINT SampleCount, D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags, UINT& NumQualityLevels) const;
+
+    // FORMAT_INFO
+    HRESULT FormatInfo(DXGI_FORMAT Format, UINT8& PlaneCount) const;
+
+    // GPU_VIRTUAL_ADDRESS_SUPPORT
+    UINT MaxGPUVirtualAddressBitsPerProcess() const noexcept;
+
+    // SHADER_MODEL
+    D3D_SHADER_MODEL HighestShaderModel() const noexcept;
+
+    // D3D12_OPTIONS1
+    BOOL WaveOps() const noexcept;
+    UINT WaveLaneCountMin() const noexcept;
+    UINT WaveLaneCountMax() const noexcept;
+    UINT TotalLaneCount() const noexcept;
+    BOOL ExpandedComputeResourceStates() const noexcept;
+    BOOL Int64ShaderOps() const noexcept;
+
+    // PROTECTED_RESOURCE_SESSION_SUPPORT
+    D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS ProtectedResourceSessionSupport(UINT NodeIndex = 0) const;
+
+    // ROOT_SIGNATURE
+    D3D_ROOT_SIGNATURE_VERSION HighestRootSignatureVersion() const noexcept;
+
+    // ARCHITECTURE1
+    BOOL TileBasedRenderer(UINT NodeIndex = 0) const;
+    BOOL UMA(UINT NodeIndex = 0) const;
+    BOOL CacheCoherentUMA(UINT NodeIndex = 0) const;
+    BOOL IsolatedMMU(UINT NodeIndex = 0) const;
+
+    // D3D12_OPTIONS2
+    BOOL DepthBoundsTestSupported() const noexcept;
+    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER ProgrammableSamplePositionsTier() const noexcept;
+
+    // SHADER_CACHE
+    D3D12_SHADER_CACHE_SUPPORT_FLAGS ShaderCacheSupportFlags() const noexcept;
+
+    // COMMAND_QUEUE_PRIORITY
+    BOOL CommandQueuePrioritySupported(D3D12_COMMAND_LIST_TYPE CommandListType, UINT Priority);
+
+    // D3D12_OPTIONS3
+    BOOL CopyQueueTimestampQueriesSupported() const noexcept;
+    BOOL CastingFullyTypedFormatSupported() const noexcept;
+    D3D12_COMMAND_LIST_SUPPORT_FLAGS WriteBufferImmediateSupportFlags() const noexcept;
+    D3D12_VIEW_INSTANCING_TIER ViewInstancingTier() const noexcept;
+    BOOL BarycentricsSupported() const noexcept;
+
+    // EXISTING_HEAPS
+    BOOL ExistingHeapsSupported() const noexcept;
+
+    // D3D12_OPTIONS4
+    BOOL MSAA64KBAlignedTextureSupported() const noexcept;
+    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER SharedResourceCompatibilityTier() const noexcept;
+    BOOL Native16BitShaderOpsSupported() const noexcept;
+
+    // SERIALIZATION
+    D3D12_HEAP_SERIALIZATION_TIER HeapSerializationTier(UINT NodeIndex = 0) const;
+
+    // CROSS_NODE
+    // CrossNodeSharingTier handled in D3D12Options
+    BOOL CrossNodeAtomicShaderInstructions() const noexcept;
+
+    // D3D12_OPTIONS5
+    BOOL SRVOnlyTiledResourceTier3() const noexcept;
+    D3D12_RENDER_PASS_TIER RenderPassesTier() const noexcept;
+    D3D12_RAYTRACING_TIER RaytracingTier() const noexcept;
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    // DISPLAYABLE
+    BOOL DisplayableTexture() const noexcept;
+    // SharedResourceCompatibilityTier handled in D3D12Options4
+#endif
+
+    // D3D12_OPTIONS6
+    BOOL AdditionalShadingRatesSupported() const noexcept;
+    BOOL PerPrimitiveShadingRateSupportedWithViewportIndexing() const noexcept;
+    D3D12_VARIABLE_SHADING_RATE_TIER VariableShadingRateTier() const noexcept;
+    UINT ShadingRateImageTileSize() const noexcept;
+    BOOL BackgroundProcessingSupported() const noexcept;
+
+    // QUERY_META_COMMAND
+    HRESULT QueryMetaCommand(D3D12_FEATURE_DATA_QUERY_META_COMMAND& dQueryMetaCommand) const;
+
+    // D3D12_OPTIONS7
+    D3D12_MESH_SHADER_TIER MeshShaderTier() const noexcept;
+    D3D12_SAMPLER_FEEDBACK_TIER SamplerFeedbackTier() const noexcept;
+
+    // PROTECTED_RESOURCE_SESSION_TYPE_COUNT
+    UINT ProtectedResourceSessionTypeCount(UINT NodeIndex = 0) const;
+
+    // PROTECTED_RESOURCE_SESSION_TYPES
+    std::vector<GUID> ProtectedResourceSessionTypes(UINT NodeIndex = 0) const;
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+    // D3D12_OPTIONS8
+    BOOL UnalignedBlockTexturesSupported() const noexcept;
+
+    // D3D12_OPTIONS9
+    BOOL MeshShaderPipelineStatsSupported() const noexcept;
+    BOOL MeshShaderSupportsFullRangeRenderTargetArrayIndex() const noexcept;
+    BOOL AtomicInt64OnTypedResourceSupported() const noexcept;
+    BOOL AtomicInt64OnGroupSharedSupported() const noexcept;
+    BOOL DerivativesInMeshAndAmplificationShadersSupported() const noexcept;
+    D3D12_WAVE_MMA_TIER WaveMMATier() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    // D3D12_OPTIONS10
+    BOOL VariableRateShadingSumCombinerSupported() const noexcept;
+    BOOL MeshShaderPerPrimitiveShadingRateSupported() const noexcept;
+
+    // D3D12_OPTIONS11
+    BOOL AtomicInt64OnDescriptorHeapResourceSupported() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 600)
+    // D3D12_OPTIONS12
+    D3D12_TRI_STATE MSPrimitivesPipelineStatisticIncludesCulledPrimitives() const noexcept;
+    BOOL EnhancedBarriersSupported() const noexcept;
+    BOOL RelaxedFormatCastingSupported() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 602)
+    // D3D12_OPTIONS13
+    BOOL UnrestrictedBufferTextureCopyPitchSupported() const noexcept;
+    BOOL UnrestrictedVertexElementAlignmentSupported() const noexcept;
+    BOOL InvertedViewportHeightFlipsYSupported() const noexcept;
+    BOOL InvertedViewportDepthFlipsZSupported() const noexcept;
+    BOOL TextureCopyBetweenDimensionsSupported() const noexcept;
+    BOOL AlphaBlendFactorSupported() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+    // D3D12_OPTIONS14
+    BOOL AdvancedTextureOpsSupported() const noexcept;
+    BOOL WriteableMSAATexturesSupported() const noexcept;
+    BOOL IndependentFrontAndBackStencilRefMaskSupported() const noexcept;
+
+    // D3D12_OPTIONS15
+    BOOL TriangleFanSupported() const noexcept;
+    BOOL DynamicIndexBufferStripCutSupported() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+    // D3D12_OPTIONS16
+    BOOL DynamicDepthBiasSupported() const noexcept;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    BOOL GPUUploadHeapSupported() const noexcept;
+
+    // D3D12_OPTIONS17
+    BOOL NonNormalizedCoordinateSamplersSupported() const noexcept;
+    BOOL ManualWriteTrackingResourceSupported() const noexcept;
+
+    // D3D12_OPTIONS18
+    BOOL RenderPassesValid() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+    BOOL MismatchingOutputDimensionsSupported() const noexcept;
+    UINT SupportedSampleCountsWithNoOutputs() const noexcept;
+    BOOL PointSamplingAddressesNeverRoundUp() const noexcept;
+    BOOL RasterizerDesc2Supported() const noexcept;
+    BOOL NarrowQuadrilateralLinesSupported() const noexcept;
+    BOOL AnisoFilterWithPointMipSupported() const noexcept;
+    UINT MaxSamplerDescriptorHeapSize() const noexcept;
+    UINT MaxSamplerDescriptorHeapSizeWithStaticSamplers() const noexcept;
+    UINT MaxViewDescriptorHeapSize() const noexcept;
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 611)
+    BOOL ComputeOnlyWriteWatchSupported() const noexcept;
+#endif
+
+private: // Private structs and helpers declaration
+    struct ProtectedResourceSessionTypesLocal : D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES
+    {
+        std::vector<GUID> TypeVec;
+    };
+
+    // Helper function to decide the highest shader model supported by the system
+    // Stores the result in m_dShaderModel
+    // Must be updated whenever a new shader model is added to the d3d12.h header
+    HRESULT QueryHighestShaderModel();
+
+    // Helper function to decide the highest root signature supported
+    // Must be updated whenever a new root signature version is added to the d3d12.h header
+    HRESULT QueryHighestRootSignatureVersion();
+
+    // Helper funcion to decide the highest feature level
+    HRESULT QueryHighestFeatureLevel();
+
+    // Helper function to initialize local protected resource session types structs
+    HRESULT QueryProtectedResourceSessionTypes(UINT NodeIndex, UINT Count);
+
+private: // Member data
+    // Pointer to the underlying device
+    ID3D12Device* m_pDevice;
+
+    // Stores the error code from initialization
+    HRESULT m_hStatus;
+
+    // Feature support data structs
+    D3D12_FEATURE_DATA_D3D12_OPTIONS m_dOptions;
+    D3D_FEATURE_LEVEL m_eMaxFeatureLevel;
+    D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT m_dGPUVASupport;
+    D3D12_FEATURE_DATA_SHADER_MODEL m_dShaderModel;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS1 m_dOptions1;
+    std::vector<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_SUPPORT> m_dProtectedResourceSessionSupport;
+    D3D12_FEATURE_DATA_ROOT_SIGNATURE m_dRootSignature;
+    std::vector<D3D12_FEATURE_DATA_ARCHITECTURE1> m_dArchitecture1;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS2 m_dOptions2;
+    D3D12_FEATURE_DATA_SHADER_CACHE m_dShaderCache;
+    D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY m_dCommandQueuePriority;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS3 m_dOptions3;
+    D3D12_FEATURE_DATA_EXISTING_HEAPS m_dExistingHeaps;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS4 m_dOptions4;
+    std::vector<D3D12_FEATURE_DATA_SERIALIZATION> m_dSerialization; // Cat2 NodeIndex
+    D3D12_FEATURE_DATA_CROSS_NODE m_dCrossNode;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS5 m_dOptions5;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    D3D12_FEATURE_DATA_DISPLAYABLE m_dDisplayable;
+#endif
+    D3D12_FEATURE_DATA_D3D12_OPTIONS6 m_dOptions6;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS7 m_dOptions7;
+    std::vector<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPE_COUNT> m_dProtectedResourceSessionTypeCount; // Cat2 NodeIndex
+    std::vector<ProtectedResourceSessionTypesLocal> m_dProtectedResourceSessionTypes; // Cat3
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS8 m_dOptions8;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS9 m_dOptions9;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS10 m_dOptions10;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS11 m_dOptions11;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 600)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS12 m_dOptions12;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 602)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS13 m_dOptions13;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS14 m_dOptions14;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS15 m_dOptions15;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS16 m_dOptions16;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS17 m_dOptions17;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS18 m_dOptions18;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS19 m_dOptions19;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 611)
+    D3D12_FEATURE_DATA_D3D12_OPTIONS20 m_dOptions20;
+#endif
+};
+
+// Implementations for CD3DX12FeatureSupport functions
+
+// Macro to set up a getter function for each entry in feature support data
+// The getter function will have the same name as the feature option name
+#define FEATURE_SUPPORT_GET(RETTYPE,FEATURE,OPTION) \
+inline RETTYPE CD3DX12FeatureSupport::OPTION() const noexcept \
+{ \
+    return FEATURE.OPTION; \
+}
+
+// Macro to set up a getter function for each entry in feature support data
+// Also specifies the name for the function which can be different from the feature name
+#define FEATURE_SUPPORT_GET_NAME(RETTYPE,FEATURE,OPTION,NAME) \
+inline RETTYPE CD3DX12FeatureSupport::NAME() const noexcept \
+{\
+    return FEATURE.OPTION; \
+}
+
+// Macro to set up a getter function for feature data indexed by the graphics node ID
+// The default parameter is 0, or the first availabe graphics device node
+#define FEATURE_SUPPORT_GET_NODE_INDEXED(RETTYPE,FEATURE,OPTION) \
+inline RETTYPE CD3DX12FeatureSupport::OPTION(UINT NodeIndex) const \
+{\
+    return FEATURE[NodeIndex].OPTION; \
+}
+
+// Macro to set up a getter function for feature data indexed by NodeIndex
+// Allows a custom name for the getter function
+#define FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(RETTYPE,FEATURE,OPTION,NAME) \
+inline RETTYPE CD3DX12FeatureSupport::NAME(UINT NodeIndex) const \
+{\
+    return FEATURE[NodeIndex].OPTION; \
+}
+
+inline CD3DX12FeatureSupport::CD3DX12FeatureSupport() noexcept
+: m_pDevice(nullptr)
+, m_hStatus(E_INVALIDARG)
+, m_dOptions{}
+, m_eMaxFeatureLevel{}
+, m_dGPUVASupport{}
+, m_dShaderModel{}
+, m_dOptions1{}
+, m_dRootSignature{}
+, m_dOptions2{}
+, m_dShaderCache{}
+, m_dCommandQueuePriority{}
+, m_dOptions3{}
+, m_dExistingHeaps{}
+, m_dOptions4{}
+, m_dCrossNode{}
+, m_dOptions5{}
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+, m_dDisplayable{}
+#endif
+, m_dOptions6{}
+, m_dOptions7{}
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+, m_dOptions8{}
+, m_dOptions9{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+, m_dOptions10{}
+, m_dOptions11{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 600)
+, m_dOptions12{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 602)
+, m_dOptions13{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+, m_dOptions14{}
+, m_dOptions15{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+, m_dOptions16{}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+, m_dOptions17{}
+#endif
+#if defined (D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+, m_dOptions18{}
+#endif
+#if defined (D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+, m_dOptions19{}
+#endif
+#if defined (D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 611)
+, m_dOptions20{}
+#endif
+{}
+
+inline HRESULT CD3DX12FeatureSupport::Init(ID3D12Device* pDevice)
+{
+    if (!pDevice)
+    {
+        m_hStatus = E_INVALIDARG;
+        return m_hStatus;
+    }
+
+    m_pDevice = pDevice;
+
+    // Initialize static feature support data structures
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_dOptions, sizeof(m_dOptions))))
+    {
+        m_dOptions = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT, &m_dGPUVASupport, sizeof(m_dGPUVASupport))))
+    {
+        m_dGPUVASupport = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &m_dOptions1, sizeof(m_dOptions1))))
+    {
+        m_dOptions1 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &m_dOptions2, sizeof(m_dOptions2))))
+    {
+        m_dOptions2 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_CACHE, &m_dShaderCache, sizeof(m_dShaderCache))))
+    {
+        m_dShaderCache = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &m_dOptions3, sizeof(m_dOptions3))))
+    {
+        m_dOptions3 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_EXISTING_HEAPS, &m_dExistingHeaps, sizeof(m_dExistingHeaps))))
+    {
+        m_dExistingHeaps = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &m_dOptions4, sizeof(m_dOptions4))))
+    {
+        m_dOptions4 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_CROSS_NODE, &m_dCrossNode, sizeof(m_dCrossNode))))
+    {
+        m_dCrossNode = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &m_dOptions5, sizeof(m_dOptions5))))
+    {
+        m_dOptions5 = {};
+    }
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_DISPLAYABLE, &m_dDisplayable, sizeof(m_dDisplayable))))
+    {
+        m_dDisplayable = {};
+    }
+#endif
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &m_dOptions6, sizeof(m_dOptions6))))
+    {
+        m_dOptions6 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &m_dOptions7, sizeof(m_dOptions7))))
+    {
+        m_dOptions7 = {};
+    }
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS8, &m_dOptions8, sizeof(m_dOptions8))))
+    {
+        m_dOptions8 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS9, &m_dOptions9, sizeof(m_dOptions9))))
+    {
+        m_dOptions9 = {};
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS10, &m_dOptions10, sizeof(m_dOptions10))))
+    {
+        m_dOptions10 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS11, &m_dOptions11, sizeof(m_dOptions11))))
+    {
+        m_dOptions11 = {};
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 600)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &m_dOptions12, sizeof(m_dOptions12))))
+    {
+        m_dOptions12 = {};
+        m_dOptions12.MSPrimitivesPipelineStatisticIncludesCulledPrimitives = D3D12_TRI_STATE::D3D12_TRI_STATE_UNKNOWN;
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 602)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS13, &m_dOptions13, sizeof(m_dOptions13))))
+    {
+        m_dOptions13 = {};
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS14, &m_dOptions14, sizeof(m_dOptions14))))
+    {
+        m_dOptions14 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS15, &m_dOptions15, sizeof(m_dOptions15))))
+    {
+        m_dOptions15 = {};
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &m_dOptions16, sizeof(m_dOptions16))))
+    {
+        m_dOptions16 = {};
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS17, &m_dOptions17, sizeof(m_dOptions17))))
+    {
+        m_dOptions17 = {};
+    }
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS18, &m_dOptions18, sizeof(m_dOptions18))))
+    {
+        m_dOptions18.RenderPassesValid = false;
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS19, &m_dOptions19, sizeof(m_dOptions19))))
+    {
+        m_dOptions19 = {};
+        m_dOptions19.SupportedSampleCountsWithNoOutputs = 1;
+        m_dOptions19.MaxSamplerDescriptorHeapSize = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE;
+        m_dOptions19.MaxSamplerDescriptorHeapSizeWithStaticSamplers = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE;
+        m_dOptions19.MaxViewDescriptorHeapSize = D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1;
+    }
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 611)
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS20, &m_dOptions20, sizeof(m_dOptions20))))
+    {
+        m_dOptions20 = {};
+    }
+#endif
+
+    // Initialize per-node feature support data structures
+    const UINT uNodeCount = m_pDevice->GetNodeCount();
+    m_dProtectedResourceSessionSupport.resize(uNodeCount);
+    m_dArchitecture1.resize(uNodeCount);
+    m_dSerialization.resize(uNodeCount);
+    m_dProtectedResourceSessionTypeCount.resize(uNodeCount);
+    m_dProtectedResourceSessionTypes.resize(uNodeCount);
+    for (UINT NodeIndex = 0; NodeIndex < uNodeCount; NodeIndex++)
+    {
+        m_dProtectedResourceSessionSupport[NodeIndex].NodeIndex = NodeIndex;
+        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_SUPPORT, &m_dProtectedResourceSessionSupport[NodeIndex], sizeof(m_dProtectedResourceSessionSupport[NodeIndex]))))
+        {
+            m_dProtectedResourceSessionSupport[NodeIndex].Support = D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAG_NONE;
+        }
+
+        m_dArchitecture1[NodeIndex].NodeIndex = NodeIndex;
+        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE1, &m_dArchitecture1[NodeIndex], sizeof(m_dArchitecture1[NodeIndex]))))
+        {
+            D3D12_FEATURE_DATA_ARCHITECTURE dArchLocal = {};
+            dArchLocal.NodeIndex = NodeIndex;
+            if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &dArchLocal, sizeof(dArchLocal))))
+            {
+                dArchLocal.TileBasedRenderer = false;
+                dArchLocal.UMA = false;
+                dArchLocal.CacheCoherentUMA = false;
+            }
+
+            m_dArchitecture1[NodeIndex].TileBasedRenderer = dArchLocal.TileBasedRenderer;
+            m_dArchitecture1[NodeIndex].UMA = dArchLocal.UMA;
+            m_dArchitecture1[NodeIndex].CacheCoherentUMA = dArchLocal.CacheCoherentUMA;
+            m_dArchitecture1[NodeIndex].IsolatedMMU = false;
+        }
+
+        m_dSerialization[NodeIndex].NodeIndex = NodeIndex;
+        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SERIALIZATION, &m_dSerialization[NodeIndex], sizeof(m_dSerialization[NodeIndex]))))
+        {
+            m_dSerialization[NodeIndex].HeapSerializationTier = D3D12_HEAP_SERIALIZATION_TIER_0;
+        }
+
+        m_dProtectedResourceSessionTypeCount[NodeIndex].NodeIndex = NodeIndex;
+        if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPE_COUNT, &m_dProtectedResourceSessionTypeCount[NodeIndex], sizeof(m_dProtectedResourceSessionTypeCount[NodeIndex]))))
+        {
+            m_dProtectedResourceSessionTypeCount[NodeIndex].Count = 0;
+        }
+
+        // Special procedure to initialize local protected resource session types structs
+        // Must wait until session type count initialized
+        QueryProtectedResourceSessionTypes(NodeIndex, m_dProtectedResourceSessionTypeCount[NodeIndex].Count);
+    }
+
+    // Initialize features that requires highest version check
+    if (FAILED(m_hStatus = QueryHighestShaderModel()))
+    {
+        return m_hStatus;
+    }
+
+    if (FAILED(m_hStatus = QueryHighestRootSignatureVersion()))
+    {
+        return m_hStatus;
+    }
+
+    // Initialize Feature Levels data
+    if (FAILED(m_hStatus = QueryHighestFeatureLevel()))
+    {
+        return m_hStatus;
+    }
+
+    return m_hStatus;
+}
+
+// 0: D3D12_OPTIONS
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, DoublePrecisionFloatShaderOps);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, OutputMergerLogicOp);
+FEATURE_SUPPORT_GET(D3D12_SHADER_MIN_PRECISION_SUPPORT, m_dOptions, MinPrecisionSupport);
+FEATURE_SUPPORT_GET(D3D12_TILED_RESOURCES_TIER, m_dOptions, TiledResourcesTier);
+FEATURE_SUPPORT_GET(D3D12_RESOURCE_BINDING_TIER, m_dOptions, ResourceBindingTier);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, PSSpecifiedStencilRefSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, TypedUAVLoadAdditionalFormats);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, ROVsSupported);
+FEATURE_SUPPORT_GET(D3D12_CONSERVATIVE_RASTERIZATION_TIER, m_dOptions, ConservativeRasterizationTier);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, StandardSwizzle64KBSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, CrossAdapterRowMajorTextureSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions, VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation);
+FEATURE_SUPPORT_GET(D3D12_RESOURCE_HEAP_TIER, m_dOptions, ResourceHeapTier);
+
+// Special procedure for handling caps that is also part of other features
+inline D3D12_CROSS_NODE_SHARING_TIER CD3DX12FeatureSupport::CrossNodeSharingTier() const noexcept
+{
+    if (m_dCrossNode.SharingTier > D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED)
+    {
+        return m_dCrossNode.SharingTier;
+    }
+    else
+    {
+        return m_dOptions.CrossNodeSharingTier;
+    }
+}
+
+inline UINT CD3DX12FeatureSupport::MaxGPUVirtualAddressBitsPerResource() const noexcept
+{
+    if (m_dOptions.MaxGPUVirtualAddressBitsPerResource > 0)
+    {
+        return m_dOptions.MaxGPUVirtualAddressBitsPerResource;
+    }
+    else
+    {
+        return m_dGPUVASupport.MaxGPUVirtualAddressBitsPerResource;
+    }
+}
+
+// 1: Architecture
+// Combined with Architecture1
+
+// 2: Feature Levels
+// Simply returns the highest supported feature level
+inline D3D_FEATURE_LEVEL CD3DX12FeatureSupport::MaxSupportedFeatureLevel() const noexcept
+{
+    return m_eMaxFeatureLevel;
+}
+
+// 3: Feature Format Support
+inline HRESULT CD3DX12FeatureSupport::FormatSupport(DXGI_FORMAT Format, D3D12_FORMAT_SUPPORT1& Support1, D3D12_FORMAT_SUPPORT2& Support2) const
+{
+    D3D12_FEATURE_DATA_FORMAT_SUPPORT dFormatSupport;
+    dFormatSupport.Format = Format;
+
+    // It is possible that the function call returns an error
+    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dFormatSupport, sizeof(D3D12_FEATURE_DATA_FORMAT_SUPPORT));
+
+    Support1 = dFormatSupport.Support1;
+    Support2 = dFormatSupport.Support2; // Two outputs. Probably better just to take in the struct as an argument?
+
+    return result;
+}
+
+// 4: Multisample Quality Levels
+inline HRESULT CD3DX12FeatureSupport::MultisampleQualityLevels(DXGI_FORMAT Format, UINT SampleCount, D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags, UINT& NumQualityLevels) const
+{
+    D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS dMultisampleQualityLevels;
+    dMultisampleQualityLevels.Format = Format;
+    dMultisampleQualityLevels.SampleCount = SampleCount;
+    dMultisampleQualityLevels.Flags = Flags;
+
+    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &dMultisampleQualityLevels, sizeof(D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS));
+
+    if (SUCCEEDED(result))
+    {
+        NumQualityLevels = dMultisampleQualityLevels.NumQualityLevels;
+    }
+    else
+    {
+        NumQualityLevels = 0;
+    }
+
+    return result;
+}
+
+// 5: Format Info
+inline HRESULT CD3DX12FeatureSupport::FormatInfo(DXGI_FORMAT Format, UINT8& PlaneCount) const
+{
+    D3D12_FEATURE_DATA_FORMAT_INFO dFormatInfo;
+    dFormatInfo.Format = Format;
+
+    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &dFormatInfo, sizeof(D3D12_FEATURE_DATA_FORMAT_INFO));
+    if (FAILED(result))
+    {
+        PlaneCount = 0;
+    }
+    else
+    {
+        PlaneCount = dFormatInfo.PlaneCount;
+    }
+    return result;
+}
+
+// 6: GPU Virtual Address Support
+// MaxGPUVirtualAddressBitsPerResource handled in D3D12Options
+FEATURE_SUPPORT_GET(UINT, m_dGPUVASupport, MaxGPUVirtualAddressBitsPerProcess);
+
+// 7: Shader Model
+inline D3D_SHADER_MODEL CD3DX12FeatureSupport::HighestShaderModel() const noexcept
+{
+    return m_dShaderModel.HighestShaderModel;
+}
+
+// 8: D3D12 Options1
+FEATURE_SUPPORT_GET(BOOL, m_dOptions1, WaveOps);
+FEATURE_SUPPORT_GET(UINT, m_dOptions1, WaveLaneCountMin);
+FEATURE_SUPPORT_GET(UINT, m_dOptions1, WaveLaneCountMax);
+FEATURE_SUPPORT_GET(UINT, m_dOptions1, TotalLaneCount);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions1, ExpandedComputeResourceStates);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions1, Int64ShaderOps);
+
+// 10: Protected Resource Session Support
+inline D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS CD3DX12FeatureSupport::ProtectedResourceSessionSupport(UINT NodeIndex) const
+{
+    return m_dProtectedResourceSessionSupport[NodeIndex].Support;
+}
+
+// 12: Root Signature
+inline D3D_ROOT_SIGNATURE_VERSION CD3DX12FeatureSupport::HighestRootSignatureVersion() const noexcept
+{
+    return m_dRootSignature.HighestVersion;
+}
+
+// 16: Architecture1
+// Same data fields can be queried from m_dArchitecture
+FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, TileBasedRenderer);
+FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, UMA);
+FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, CacheCoherentUMA);
+FEATURE_SUPPORT_GET_NODE_INDEXED(BOOL, m_dArchitecture1, IsolatedMMU);
+
+// 18: D3D12 Options2
+FEATURE_SUPPORT_GET(BOOL, m_dOptions2, DepthBoundsTestSupported);
+FEATURE_SUPPORT_GET(D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER, m_dOptions2, ProgrammableSamplePositionsTier);
+
+// 19: Shader Cache
+FEATURE_SUPPORT_GET_NAME(D3D12_SHADER_CACHE_SUPPORT_FLAGS, m_dShaderCache, SupportFlags, ShaderCacheSupportFlags);
+
+// 20: Command Queue Priority
+inline BOOL CD3DX12FeatureSupport::CommandQueuePrioritySupported(D3D12_COMMAND_LIST_TYPE CommandListType, UINT Priority)
+{
+    m_dCommandQueuePriority.CommandListType = CommandListType;
+    m_dCommandQueuePriority.Priority = Priority;
+
+    if (FAILED(m_pDevice->CheckFeatureSupport(D3D12_FEATURE_COMMAND_QUEUE_PRIORITY, &m_dCommandQueuePriority, sizeof(D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY))))
+    {
+        return false;
+    }
+
+    return m_dCommandQueuePriority.PriorityForTypeIsSupported;
+}
+
+// 21: D3D12 Options3
+FEATURE_SUPPORT_GET(BOOL, m_dOptions3, CopyQueueTimestampQueriesSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions3, CastingFullyTypedFormatSupported);
+FEATURE_SUPPORT_GET(D3D12_COMMAND_LIST_SUPPORT_FLAGS, m_dOptions3, WriteBufferImmediateSupportFlags);
+FEATURE_SUPPORT_GET(D3D12_VIEW_INSTANCING_TIER, m_dOptions3, ViewInstancingTier);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions3, BarycentricsSupported);
+
+// 22: Existing Heaps
+FEATURE_SUPPORT_GET_NAME(BOOL, m_dExistingHeaps, Supported, ExistingHeapsSupported);
+
+// 23: D3D12 Options4
+FEATURE_SUPPORT_GET(BOOL, m_dOptions4, MSAA64KBAlignedTextureSupported);
+FEATURE_SUPPORT_GET(D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER, m_dOptions4, SharedResourceCompatibilityTier);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions4, Native16BitShaderOpsSupported);
+
+// 24: Serialization
+FEATURE_SUPPORT_GET_NODE_INDEXED(D3D12_HEAP_SERIALIZATION_TIER, m_dSerialization, HeapSerializationTier);
+
+// 25: Cross Node
+// CrossNodeSharingTier handled in D3D12Options
+FEATURE_SUPPORT_GET_NAME(BOOL, m_dCrossNode, AtomicShaderInstructions, CrossNodeAtomicShaderInstructions);
+
+// 27: D3D12 Options5
+FEATURE_SUPPORT_GET(BOOL, m_dOptions5, SRVOnlyTiledResourceTier3);
+FEATURE_SUPPORT_GET(D3D12_RENDER_PASS_TIER, m_dOptions5, RenderPassesTier);
+FEATURE_SUPPORT_GET(D3D12_RAYTRACING_TIER, m_dOptions5, RaytracingTier);
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+// 28: Displayable
+FEATURE_SUPPORT_GET(BOOL, m_dDisplayable, DisplayableTexture);
+// SharedResourceCompatibilityTier handled in D3D12Options4
+#endif
+
+// 30: D3D12 Options6
+FEATURE_SUPPORT_GET(BOOL, m_dOptions6, AdditionalShadingRatesSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions6, PerPrimitiveShadingRateSupportedWithViewportIndexing);
+FEATURE_SUPPORT_GET(D3D12_VARIABLE_SHADING_RATE_TIER, m_dOptions6, VariableShadingRateTier);
+FEATURE_SUPPORT_GET(UINT, m_dOptions6, ShadingRateImageTileSize);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions6, BackgroundProcessingSupported);
+
+// 31: Query Meta Command
+// Keep the original call routine
+inline HRESULT CD3DX12FeatureSupport::QueryMetaCommand(D3D12_FEATURE_DATA_QUERY_META_COMMAND& dQueryMetaCommand) const
+{
+    return m_pDevice->CheckFeatureSupport(D3D12_FEATURE_QUERY_META_COMMAND, &dQueryMetaCommand, sizeof(D3D12_FEATURE_DATA_QUERY_META_COMMAND));
+}
+
+// 32: D3D12 Options7
+FEATURE_SUPPORT_GET(D3D12_MESH_SHADER_TIER, m_dOptions7, MeshShaderTier);
+FEATURE_SUPPORT_GET(D3D12_SAMPLER_FEEDBACK_TIER, m_dOptions7, SamplerFeedbackTier);
+
+// 33: Protected Resource Session Type Count
+FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(UINT, m_dProtectedResourceSessionTypeCount, Count, ProtectedResourceSessionTypeCount);
+
+// 34: Protected Resource Session Types
+FEATURE_SUPPORT_GET_NODE_INDEXED_NAME(std::vector<GUID>, m_dProtectedResourceSessionTypes, TypeVec, ProtectedResourceSessionTypes);
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+// 36: Options8
+FEATURE_SUPPORT_GET(BOOL, m_dOptions8, UnalignedBlockTexturesSupported);
+
+// 37: Options9
+FEATURE_SUPPORT_GET(BOOL, m_dOptions9, MeshShaderPipelineStatsSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions9, MeshShaderSupportsFullRangeRenderTargetArrayIndex);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions9, AtomicInt64OnTypedResourceSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions9, AtomicInt64OnGroupSharedSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions9, DerivativesInMeshAndAmplificationShadersSupported);
+FEATURE_SUPPORT_GET(D3D12_WAVE_MMA_TIER, m_dOptions9, WaveMMATier);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 4)
+// 39: Options10
+FEATURE_SUPPORT_GET(BOOL, m_dOptions10, VariableRateShadingSumCombinerSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions10, MeshShaderPerPrimitiveShadingRateSupported);
+
+// 40: Options11
+FEATURE_SUPPORT_GET(BOOL, m_dOptions11, AtomicInt64OnDescriptorHeapResourceSupported);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 600)
+// 41: Options12
+FEATURE_SUPPORT_GET(D3D12_TRI_STATE, m_dOptions12, MSPrimitivesPipelineStatisticIncludesCulledPrimitives);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions12, EnhancedBarriersSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions12, RelaxedFormatCastingSupported);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 602)
+// 42: Options13
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, UnrestrictedBufferTextureCopyPitchSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, UnrestrictedVertexElementAlignmentSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, InvertedViewportHeightFlipsYSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, InvertedViewportDepthFlipsZSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, TextureCopyBetweenDimensionsSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions13, AlphaBlendFactorSupported);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+// 43: Options14
+FEATURE_SUPPORT_GET(BOOL, m_dOptions14, AdvancedTextureOpsSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions14, WriteableMSAATexturesSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions14, IndependentFrontAndBackStencilRefMaskSupported);
+
+// 44: Options15
+FEATURE_SUPPORT_GET(BOOL, m_dOptions15, TriangleFanSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions15, DynamicIndexBufferStripCutSupported);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+// 45: Options16
+FEATURE_SUPPORT_GET(BOOL, m_dOptions16, DynamicDepthBiasSupported);
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+FEATURE_SUPPORT_GET(BOOL, m_dOptions16, GPUUploadHeapSupported);
+
+// 46: Options17
+FEATURE_SUPPORT_GET(BOOL, m_dOptions17, NonNormalizedCoordinateSamplersSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions17, ManualWriteTrackingResourceSupported);
+
+// 47: Option18
+FEATURE_SUPPORT_GET(BOOL, m_dOptions18, RenderPassesValid);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+FEATURE_SUPPORT_GET(BOOL, m_dOptions19, MismatchingOutputDimensionsSupported);
+FEATURE_SUPPORT_GET(UINT, m_dOptions19, SupportedSampleCountsWithNoOutputs);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions19, PointSamplingAddressesNeverRoundUp);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions19, RasterizerDesc2Supported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions19, NarrowQuadrilateralLinesSupported);
+FEATURE_SUPPORT_GET(BOOL, m_dOptions19, AnisoFilterWithPointMipSupported);
+FEATURE_SUPPORT_GET(UINT, m_dOptions19, MaxSamplerDescriptorHeapSize);
+FEATURE_SUPPORT_GET(UINT, m_dOptions19, MaxSamplerDescriptorHeapSizeWithStaticSamplers);
+FEATURE_SUPPORT_GET(UINT, m_dOptions19, MaxViewDescriptorHeapSize);
+#endif
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 611)
+// 49: Options20
+FEATURE_SUPPORT_GET(BOOL, m_dOptions20, ComputeOnlyWriteWatchSupported);
+#endif
+
+// Helper function to decide the highest shader model supported by the system
+// Stores the result in m_dShaderModel
+// Must be updated whenever a new shader model is added to the d3d12.h header
+inline HRESULT CD3DX12FeatureSupport::QueryHighestShaderModel()
+{
+    // Check support in descending order
+    HRESULT result;
+
+    const D3D_SHADER_MODEL allModelVersions[] =
+    {
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+        D3D_SHADER_MODEL_6_8,
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+        D3D_SHADER_MODEL_6_7,
+#endif
+        D3D_SHADER_MODEL_6_6,
+        D3D_SHADER_MODEL_6_5,
+        D3D_SHADER_MODEL_6_4,
+        D3D_SHADER_MODEL_6_3,
+        D3D_SHADER_MODEL_6_2,
+        D3D_SHADER_MODEL_6_1,
+        D3D_SHADER_MODEL_6_0,
+        D3D_SHADER_MODEL_5_1
+    };
+    constexpr size_t numModelVersions = sizeof(allModelVersions) / sizeof(D3D_SHADER_MODEL);
+
+    for (size_t i = 0; i < numModelVersions; i++)
+    {
+        m_dShaderModel.HighestShaderModel = allModelVersions[i];
+        result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &m_dShaderModel, sizeof(D3D12_FEATURE_DATA_SHADER_MODEL));
+        if (result != E_INVALIDARG)
+        {
+            // Indicates that the version is recognizable by the runtime and stored in the struct
+            // Also terminate on unexpected error code
+            if (FAILED(result))
+            {
+                m_dShaderModel.HighestShaderModel = static_cast<D3D_SHADER_MODEL>(0);
+            }
+            return result;
+        }
+    }
+
+    // Shader model may not be supported. Continue the rest initializations
+    m_dShaderModel.HighestShaderModel = static_cast<D3D_SHADER_MODEL>(0);
+    return S_OK;
+}
+
+// Helper function to decide the highest root signature supported
+// Must be updated whenever a new root signature version is added to the d3d12.h header
+inline HRESULT CD3DX12FeatureSupport::QueryHighestRootSignatureVersion()
+{
+    HRESULT result;
+
+    const D3D_ROOT_SIGNATURE_VERSION allRootSignatureVersions[] =
+    {
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+        D3D_ROOT_SIGNATURE_VERSION_1_2,
+#endif
+        D3D_ROOT_SIGNATURE_VERSION_1_1,
+        D3D_ROOT_SIGNATURE_VERSION_1_0,
+        D3D_ROOT_SIGNATURE_VERSION_1,
+    };
+    constexpr size_t numRootSignatureVersions = sizeof(allRootSignatureVersions) / sizeof(D3D_ROOT_SIGNATURE_VERSION);
+
+    for (size_t i = 0; i < numRootSignatureVersions; i++)
+    {
+        m_dRootSignature.HighestVersion = allRootSignatureVersions[i];
+        result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &m_dRootSignature, sizeof(D3D12_FEATURE_DATA_ROOT_SIGNATURE));
+        if (result != E_INVALIDARG)
+        {
+            if (FAILED(result))
+            {
+                m_dRootSignature.HighestVersion = static_cast<D3D_ROOT_SIGNATURE_VERSION>(0);
+            }
+            // If succeeded, the highest version is already written into the member struct
+            return result;
+        }
+    }
+
+    // No version left. Set to invalid value and continue.
+    m_dRootSignature.HighestVersion = static_cast<D3D_ROOT_SIGNATURE_VERSION>(0);
+    return S_OK;
+}
+
+// Helper funcion to decide the highest feature level
+inline HRESULT CD3DX12FeatureSupport::QueryHighestFeatureLevel()
+{
+    HRESULT result;
+
+    // Check against a list of all feature levels present in d3dcommon.h
+    // Needs to be updated for future feature levels
+    const D3D_FEATURE_LEVEL allLevels[] =
+    {
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3)
+        D3D_FEATURE_LEVEL_12_2,
+#endif
+        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,
+        D3D_FEATURE_LEVEL_1_0_CORE,
+        D3D_FEATURE_LEVEL_1_0_GENERIC
+    };
+
+    D3D12_FEATURE_DATA_FEATURE_LEVELS dFeatureLevel;
+    dFeatureLevel.NumFeatureLevels = static_cast<UINT>(sizeof(allLevels) / sizeof(D3D_FEATURE_LEVEL));
+    dFeatureLevel.pFeatureLevelsRequested = allLevels;
+
+    result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &dFeatureLevel, sizeof(D3D12_FEATURE_DATA_FEATURE_LEVELS));
+    if (SUCCEEDED(result))
+    {
+        m_eMaxFeatureLevel = dFeatureLevel.MaxSupportedFeatureLevel;
+    }
+    else
+    {
+        m_eMaxFeatureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
+
+        if (result == DXGI_ERROR_UNSUPPORTED)
+        {
+            // Indicates that none supported. Continue initialization
+            result = S_OK;
+        }
+    }
+    return result;
+}
+
+// Helper function to initialize local protected resource session types structs
+inline HRESULT CD3DX12FeatureSupport::QueryProtectedResourceSessionTypes(UINT NodeIndex, UINT Count)
+{
+    auto& CurrentPRSTypes = m_dProtectedResourceSessionTypes[NodeIndex];
+    CurrentPRSTypes.NodeIndex = NodeIndex;
+    CurrentPRSTypes.Count = Count;
+    CurrentPRSTypes.TypeVec.resize(CurrentPRSTypes.Count);
+    CurrentPRSTypes.pTypes = CurrentPRSTypes.TypeVec.data();
+
+    HRESULT result = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPES, &m_dProtectedResourceSessionTypes[NodeIndex], sizeof(D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES));
+    if (FAILED(result))
+    {
+        // Resize TypeVec to empty
+        CurrentPRSTypes.TypeVec.clear();
+    }
+
+    return result;
+}
+
+#undef FEATURE_SUPPORT_GET
+#undef FEATURE_SUPPORT_GET_NAME
+#undef FEATURE_SUPPORT_GET_NODE_INDEXED
+#undef FEATURE_SUPPORT_GET_NODE_INDEXED_NAME
+
+// end CD3DX12FeatureSupport

+ 1535 - 0
thirdparty/directx_headers/include/directx/d3dx12_core.h

@@ -0,0 +1,1535 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include <string.h>
+#include "d3d12.h"
+#include "d3dx12_default.h"
+
+//------------------------------------------------------------------------------------------------
+#ifndef D3DX12_ASSERT
+  #ifdef assert
+    #define D3DX12_ASSERT(x) assert(x)
+  #else
+    #define D3DX12_ASSERT(x)
+  #endif
+#endif
+
+//------------------------------------------------------------------------------------------------
+template <typename t_CommandListType>
+inline ID3D12CommandList * const * CommandListCast(t_CommandListType * const * pp) noexcept
+{
+    // This cast is useful for passing strongly typed command list pointers into
+    // ExecuteCommandLists.
+    // This cast is valid as long as the const-ness is respected. D3D12 APIs do
+    // respect the const-ness of their arguments.
+    return reinterpret_cast<ID3D12CommandList * const *>(pp);
+}
+
+//------------------------------------------------------------------------------------------------
+inline bool operator==( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept
+{
+    return l.TopLeftX == r.TopLeftX && l.TopLeftY == r.TopLeftY && l.Width == r.Width &&
+        l.Height == r.Height && l.MinDepth == r.MinDepth && l.MaxDepth == r.MaxDepth;
+}
+
+//------------------------------------------------------------------------------------------------
+inline bool operator!=( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RECT : public D3D12_RECT
+{
+    CD3DX12_RECT() = default;
+    explicit CD3DX12_RECT( const D3D12_RECT& o ) noexcept :
+        D3D12_RECT( o )
+    {}
+    explicit CD3DX12_RECT(
+        LONG Left,
+        LONG Top,
+        LONG Right,
+        LONG Bottom ) noexcept
+    {
+        left = Left;
+        top = Top;
+        right = Right;
+        bottom = Bottom;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_VIEWPORT : public D3D12_VIEWPORT
+{
+    CD3DX12_VIEWPORT() = default;
+    explicit CD3DX12_VIEWPORT( const D3D12_VIEWPORT& o ) noexcept :
+        D3D12_VIEWPORT( o )
+    {}
+    explicit CD3DX12_VIEWPORT(
+        FLOAT topLeftX,
+        FLOAT topLeftY,
+        FLOAT width,
+        FLOAT height,
+        FLOAT minDepth = D3D12_MIN_DEPTH,
+        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept
+    {
+        TopLeftX = topLeftX;
+        TopLeftY = topLeftY;
+        Width = width;
+        Height = height;
+        MinDepth = minDepth;
+        MaxDepth = maxDepth;
+    }
+    explicit CD3DX12_VIEWPORT(
+        _In_ ID3D12Resource* pResource,
+        UINT mipSlice = 0,
+        FLOAT topLeftX = 0.0f,
+        FLOAT topLeftY = 0.0f,
+        FLOAT minDepth = D3D12_MIN_DEPTH,
+        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept
+    {
+#if defined(_MSC_VER) || !defined(_WIN32)
+        const auto Desc = pResource->GetDesc();
+#else
+        D3D12_RESOURCE_DESC tmpDesc;
+        const auto& Desc = *pResource->GetDesc(&tmpDesc);
+#endif
+        const UINT64 SubresourceWidth = Desc.Width >> mipSlice;
+        const UINT64 SubresourceHeight = Desc.Height >> mipSlice;
+        switch (Desc.Dimension)
+        {
+        case D3D12_RESOURCE_DIMENSION_BUFFER:
+            TopLeftX = topLeftX;
+            TopLeftY = 0.0f;
+            Width = float(Desc.Width) - topLeftX;
+            Height = 1.0f;
+            break;
+        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+            TopLeftX = topLeftX;
+            TopLeftY = 0.0f;
+            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;
+            Height = 1.0f;
+            break;
+        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+            TopLeftX = topLeftX;
+            TopLeftY = topLeftY;
+            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;
+            Height = (SubresourceHeight ? float(SubresourceHeight) : 1.0f) - topLeftY;
+            break;
+        default: break;
+        }
+
+        MinDepth = minDepth;
+        MaxDepth = maxDepth;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_BOX : public D3D12_BOX
+{
+    CD3DX12_BOX() = default;
+    explicit CD3DX12_BOX( const D3D12_BOX& o ) noexcept :
+        D3D12_BOX( o )
+    {}
+    explicit CD3DX12_BOX(
+        LONG Left,
+        LONG Right ) noexcept
+    {
+        left = static_cast<UINT>(Left);
+        top = 0;
+        front = 0;
+        right = static_cast<UINT>(Right);
+        bottom = 1;
+        back = 1;
+    }
+    explicit CD3DX12_BOX(
+        LONG Left,
+        LONG Top,
+        LONG Right,
+        LONG Bottom ) noexcept
+    {
+        left = static_cast<UINT>(Left);
+        top = static_cast<UINT>(Top);
+        front = 0;
+        right = static_cast<UINT>(Right);
+        bottom = static_cast<UINT>(Bottom);
+        back = 1;
+    }
+    explicit CD3DX12_BOX(
+        LONG Left,
+        LONG Top,
+        LONG Front,
+        LONG Right,
+        LONG Bottom,
+        LONG Back ) noexcept
+    {
+        left = static_cast<UINT>(Left);
+        top = static_cast<UINT>(Top);
+        front = static_cast<UINT>(Front);
+        right = static_cast<UINT>(Right);
+        bottom = static_cast<UINT>(Bottom);
+        back = static_cast<UINT>(Back);
+    }
+};
+inline bool operator==( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept
+{
+    return l.left == r.left && l.top == r.top && l.front == r.front &&
+        l.right == r.right && l.bottom == r.bottom && l.back == r.back;
+}
+inline bool operator!=( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_DEPTH_STENCIL_DESC : public D3D12_DEPTH_STENCIL_DESC
+{
+    CD3DX12_DEPTH_STENCIL_DESC() = default;
+    explicit CD3DX12_DEPTH_STENCIL_DESC( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept :
+        D3D12_DEPTH_STENCIL_DESC( o )
+    {}
+    explicit CD3DX12_DEPTH_STENCIL_DESC( CD3DX12_DEFAULT ) noexcept
+    {
+        DepthEnable = TRUE;
+        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+        StencilEnable = FALSE;
+        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
+        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
+        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
+        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
+        FrontFace = defaultStencilOp;
+        BackFace = defaultStencilOp;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC(
+        BOOL depthEnable,
+        D3D12_DEPTH_WRITE_MASK depthWriteMask,
+        D3D12_COMPARISON_FUNC depthFunc,
+        BOOL stencilEnable,
+        UINT8 stencilReadMask,
+        UINT8 stencilWriteMask,
+        D3D12_STENCIL_OP frontStencilFailOp,
+        D3D12_STENCIL_OP frontStencilDepthFailOp,
+        D3D12_STENCIL_OP frontStencilPassOp,
+        D3D12_COMPARISON_FUNC frontStencilFunc,
+        D3D12_STENCIL_OP backStencilFailOp,
+        D3D12_STENCIL_OP backStencilDepthFailOp,
+        D3D12_STENCIL_OP backStencilPassOp,
+        D3D12_COMPARISON_FUNC backStencilFunc ) noexcept
+    {
+        DepthEnable = depthEnable;
+        DepthWriteMask = depthWriteMask;
+        DepthFunc = depthFunc;
+        StencilEnable = stencilEnable;
+        StencilReadMask = stencilReadMask;
+        StencilWriteMask = stencilWriteMask;
+        FrontFace.StencilFailOp = frontStencilFailOp;
+        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
+        FrontFace.StencilPassOp = frontStencilPassOp;
+        FrontFace.StencilFunc = frontStencilFunc;
+        BackFace.StencilFailOp = backStencilFailOp;
+        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
+        BackFace.StencilPassOp = backStencilPassOp;
+        BackFace.StencilFunc = backStencilFunc;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_DEPTH_STENCIL_DESC1 : public D3D12_DEPTH_STENCIL_DESC1
+{
+    CD3DX12_DEPTH_STENCIL_DESC1() = default;
+    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept :
+        D3D12_DEPTH_STENCIL_DESC1( o )
+    {}
+    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept
+    {
+        DepthEnable                  = o.DepthEnable;
+        DepthWriteMask               = o.DepthWriteMask;
+        DepthFunc                    = o.DepthFunc;
+        StencilEnable                = o.StencilEnable;
+        StencilReadMask              = o.StencilReadMask;
+        StencilWriteMask             = o.StencilWriteMask;
+        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
+        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
+        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
+        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
+        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
+        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
+        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
+        BackFace.StencilFunc         = o.BackFace.StencilFunc;
+        DepthBoundsTestEnable        = FALSE;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC1( CD3DX12_DEFAULT ) noexcept
+    {
+        DepthEnable = TRUE;
+        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+        StencilEnable = FALSE;
+        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
+        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
+        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
+        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
+        FrontFace = defaultStencilOp;
+        BackFace = defaultStencilOp;
+        DepthBoundsTestEnable = FALSE;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC1(
+        BOOL depthEnable,
+        D3D12_DEPTH_WRITE_MASK depthWriteMask,
+        D3D12_COMPARISON_FUNC depthFunc,
+        BOOL stencilEnable,
+        UINT8 stencilReadMask,
+        UINT8 stencilWriteMask,
+        D3D12_STENCIL_OP frontStencilFailOp,
+        D3D12_STENCIL_OP frontStencilDepthFailOp,
+        D3D12_STENCIL_OP frontStencilPassOp,
+        D3D12_COMPARISON_FUNC frontStencilFunc,
+        D3D12_STENCIL_OP backStencilFailOp,
+        D3D12_STENCIL_OP backStencilDepthFailOp,
+        D3D12_STENCIL_OP backStencilPassOp,
+        D3D12_COMPARISON_FUNC backStencilFunc,
+        BOOL depthBoundsTestEnable ) noexcept
+    {
+        DepthEnable = depthEnable;
+        DepthWriteMask = depthWriteMask;
+        DepthFunc = depthFunc;
+        StencilEnable = stencilEnable;
+        StencilReadMask = stencilReadMask;
+        StencilWriteMask = stencilWriteMask;
+        FrontFace.StencilFailOp = frontStencilFailOp;
+        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
+        FrontFace.StencilPassOp = frontStencilPassOp;
+        FrontFace.StencilFunc = frontStencilFunc;
+        BackFace.StencilFailOp = backStencilFailOp;
+        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
+        BackFace.StencilPassOp = backStencilPassOp;
+        BackFace.StencilFunc = backStencilFunc;
+        DepthBoundsTestEnable = depthBoundsTestEnable;
+    }
+    operator D3D12_DEPTH_STENCIL_DESC() const noexcept
+    {
+        D3D12_DEPTH_STENCIL_DESC D;
+        D.DepthEnable                  = DepthEnable;
+        D.DepthWriteMask               = DepthWriteMask;
+        D.DepthFunc                    = DepthFunc;
+        D.StencilEnable                = StencilEnable;
+        D.StencilReadMask              = StencilReadMask;
+        D.StencilWriteMask             = StencilWriteMask;
+        D.FrontFace.StencilFailOp      = FrontFace.StencilFailOp;
+        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;
+        D.FrontFace.StencilPassOp      = FrontFace.StencilPassOp;
+        D.FrontFace.StencilFunc        = FrontFace.StencilFunc;
+        D.BackFace.StencilFailOp       = BackFace.StencilFailOp;
+        D.BackFace.StencilDepthFailOp  = BackFace.StencilDepthFailOp;
+        D.BackFace.StencilPassOp       = BackFace.StencilPassOp;
+        D.BackFace.StencilFunc         = BackFace.StencilFunc;
+        return D;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+struct CD3DX12_DEPTH_STENCIL_DESC2 : public D3D12_DEPTH_STENCIL_DESC2
+{
+    CD3DX12_DEPTH_STENCIL_DESC2() = default;
+    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC2& o ) noexcept :
+        D3D12_DEPTH_STENCIL_DESC2( o )
+    {}
+    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept
+    {
+        DepthEnable                  = o.DepthEnable;
+        DepthWriteMask               = o.DepthWriteMask;
+        DepthFunc                    = o.DepthFunc;
+        StencilEnable                = o.StencilEnable;
+        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
+        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
+        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
+        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
+        FrontFace.StencilReadMask    = o.StencilReadMask;
+        FrontFace.StencilWriteMask   = o.StencilWriteMask;
+
+        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
+        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
+        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
+        BackFace.StencilFunc         = o.BackFace.StencilFunc;
+        BackFace.StencilReadMask     = o.StencilReadMask;
+        BackFace.StencilWriteMask    = o.StencilWriteMask;
+        DepthBoundsTestEnable        = o.DepthBoundsTestEnable;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC2( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept
+    {
+        DepthEnable                  = o.DepthEnable;
+        DepthWriteMask               = o.DepthWriteMask;
+        DepthFunc                    = o.DepthFunc;
+        StencilEnable                = o.StencilEnable;
+
+        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;
+        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;
+        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;
+        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;
+        FrontFace.StencilReadMask    = o.StencilReadMask;
+        FrontFace.StencilWriteMask   = o.StencilWriteMask;
+
+        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;
+        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;
+        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;
+        BackFace.StencilFunc         = o.BackFace.StencilFunc;
+        BackFace.StencilReadMask     = o.StencilReadMask;
+        BackFace.StencilWriteMask    = o.StencilWriteMask;
+
+        DepthBoundsTestEnable        = FALSE;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC2( CD3DX12_DEFAULT ) noexcept
+    {
+        DepthEnable = TRUE;
+        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+        DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+        StencilEnable = FALSE;
+        const D3D12_DEPTH_STENCILOP_DESC1 defaultStencilOp =
+        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS, D3D12_DEFAULT_STENCIL_READ_MASK, D3D12_DEFAULT_STENCIL_WRITE_MASK };
+        FrontFace = defaultStencilOp;
+        BackFace = defaultStencilOp;
+        DepthBoundsTestEnable = FALSE;
+    }
+    explicit CD3DX12_DEPTH_STENCIL_DESC2(
+        BOOL depthEnable,
+        D3D12_DEPTH_WRITE_MASK depthWriteMask,
+        D3D12_COMPARISON_FUNC depthFunc,
+        BOOL stencilEnable,
+        D3D12_STENCIL_OP frontStencilFailOp,
+        D3D12_STENCIL_OP frontStencilDepthFailOp,
+        D3D12_STENCIL_OP frontStencilPassOp,
+        D3D12_COMPARISON_FUNC frontStencilFunc,
+        UINT8 frontStencilReadMask,
+        UINT8 frontStencilWriteMask,
+        D3D12_STENCIL_OP backStencilFailOp,
+        D3D12_STENCIL_OP backStencilDepthFailOp,
+        D3D12_STENCIL_OP backStencilPassOp,
+        D3D12_COMPARISON_FUNC backStencilFunc,
+        UINT8 backStencilReadMask,
+        UINT8 backStencilWriteMask,
+        BOOL depthBoundsTestEnable ) noexcept
+    {
+        DepthEnable = depthEnable;
+        DepthWriteMask = depthWriteMask;
+        DepthFunc = depthFunc;
+        StencilEnable = stencilEnable;
+
+        FrontFace.StencilFailOp = frontStencilFailOp;
+        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;
+        FrontFace.StencilPassOp = frontStencilPassOp;
+        FrontFace.StencilFunc = frontStencilFunc;
+        FrontFace.StencilReadMask = frontStencilReadMask;
+        FrontFace.StencilWriteMask = frontStencilWriteMask;
+
+        BackFace.StencilFailOp = backStencilFailOp;
+        BackFace.StencilDepthFailOp = backStencilDepthFailOp;
+        BackFace.StencilPassOp = backStencilPassOp;
+        BackFace.StencilFunc = backStencilFunc;
+        BackFace.StencilReadMask = backStencilReadMask;
+        BackFace.StencilWriteMask = backStencilWriteMask;
+
+        DepthBoundsTestEnable = depthBoundsTestEnable;
+    }
+
+    operator D3D12_DEPTH_STENCIL_DESC() const noexcept
+    {
+        D3D12_DEPTH_STENCIL_DESC D;
+        D.DepthEnable = DepthEnable;
+        D.DepthWriteMask = DepthWriteMask;
+        D.DepthFunc = DepthFunc;
+        D.StencilEnable = StencilEnable;
+        D.StencilReadMask = FrontFace.StencilReadMask;
+        D.StencilWriteMask = FrontFace.StencilWriteMask;
+        D.FrontFace.StencilFailOp = FrontFace.StencilFailOp;
+        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;
+        D.FrontFace.StencilPassOp = FrontFace.StencilPassOp;
+        D.FrontFace.StencilFunc = FrontFace.StencilFunc;
+        D.BackFace.StencilFailOp = BackFace.StencilFailOp;
+        D.BackFace.StencilDepthFailOp = BackFace.StencilDepthFailOp;
+        D.BackFace.StencilPassOp = BackFace.StencilPassOp;
+        D.BackFace.StencilFunc = BackFace.StencilFunc;
+        return D;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 606
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_BLEND_DESC : public D3D12_BLEND_DESC
+{
+    CD3DX12_BLEND_DESC() = default;
+    explicit CD3DX12_BLEND_DESC( const D3D12_BLEND_DESC& o ) noexcept :
+        D3D12_BLEND_DESC( o )
+    {}
+    explicit CD3DX12_BLEND_DESC( CD3DX12_DEFAULT ) noexcept
+    {
+        AlphaToCoverageEnable = FALSE;
+        IndependentBlendEnable = FALSE;
+        const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =
+        {
+            FALSE,FALSE,
+            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+            D3D12_LOGIC_OP_NOOP,
+            D3D12_COLOR_WRITE_ENABLE_ALL,
+        };
+        for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
+            RenderTarget[ i ] = defaultRenderTargetBlendDesc;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RASTERIZER_DESC : public D3D12_RASTERIZER_DESC
+{
+    CD3DX12_RASTERIZER_DESC() = default;
+    explicit CD3DX12_RASTERIZER_DESC( const D3D12_RASTERIZER_DESC& o ) noexcept :
+        D3D12_RASTERIZER_DESC( o )
+    {}
+    explicit CD3DX12_RASTERIZER_DESC( CD3DX12_DEFAULT ) noexcept
+    {
+        FillMode = D3D12_FILL_MODE_SOLID;
+        CullMode = D3D12_CULL_MODE_BACK;
+        FrontCounterClockwise = FALSE;
+        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+        DepthClipEnable = TRUE;
+        MultisampleEnable = FALSE;
+        AntialiasedLineEnable = FALSE;
+        ForcedSampleCount = 0;
+        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+    }
+    explicit CD3DX12_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) noexcept
+    {
+        FillMode = fillMode;
+        CullMode = cullMode;
+        FrontCounterClockwise = frontCounterClockwise;
+        DepthBias = depthBias;
+        DepthBiasClamp = depthBiasClamp;
+        SlopeScaledDepthBias = slopeScaledDepthBias;
+        DepthClipEnable = depthClipEnable;
+        MultisampleEnable = multisampleEnable;
+        AntialiasedLineEnable = antialiasedLineEnable;
+        ForcedSampleCount = forcedSampleCount;
+        ConservativeRaster = conservativeRaster;
+    }
+};
+
+
+//------------------------------------------------------------------------------------------------
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+struct CD3DX12_RASTERIZER_DESC1 : public D3D12_RASTERIZER_DESC1
+{
+    CD3DX12_RASTERIZER_DESC1() = default;
+    explicit CD3DX12_RASTERIZER_DESC1(const D3D12_RASTERIZER_DESC1& o) noexcept :
+        D3D12_RASTERIZER_DESC1(o)
+
+    {
+    }
+    explicit CD3DX12_RASTERIZER_DESC1(const D3D12_RASTERIZER_DESC& o) noexcept
+    {
+        FillMode = o.FillMode;
+        CullMode = o.CullMode;
+        FrontCounterClockwise = o.FrontCounterClockwise;
+        DepthBias = static_cast<FLOAT>(o.DepthBias);
+        DepthBiasClamp = o.DepthBiasClamp;
+        SlopeScaledDepthBias = o.SlopeScaledDepthBias;
+        DepthClipEnable = o.DepthClipEnable;
+        MultisampleEnable = o.MultisampleEnable;
+        AntialiasedLineEnable = o.AntialiasedLineEnable;
+        ForcedSampleCount = o.ForcedSampleCount;
+        ConservativeRaster = o.ConservativeRaster;
+    }
+    explicit CD3DX12_RASTERIZER_DESC1(CD3DX12_DEFAULT) noexcept
+    {
+        FillMode = D3D12_FILL_MODE_SOLID;
+        CullMode = D3D12_CULL_MODE_BACK;
+        FrontCounterClockwise = FALSE;
+        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+        DepthClipEnable = TRUE;
+        MultisampleEnable = FALSE;
+        AntialiasedLineEnable = FALSE;
+        ForcedSampleCount = 0;
+        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+    }
+    explicit CD3DX12_RASTERIZER_DESC1(
+        D3D12_FILL_MODE fillMode,
+        D3D12_CULL_MODE cullMode,
+        BOOL frontCounterClockwise,
+        FLOAT depthBias,
+        FLOAT depthBiasClamp,
+        FLOAT slopeScaledDepthBias,
+        BOOL depthClipEnable,
+        BOOL multisampleEnable,
+        BOOL antialiasedLineEnable,
+        UINT forcedSampleCount,
+        D3D12_CONSERVATIVE_RASTERIZATION_MODE conservativeRaster) noexcept
+    {
+        FillMode = fillMode;
+        CullMode = cullMode;
+        FrontCounterClockwise = frontCounterClockwise;
+        DepthBias = depthBias;
+        DepthBiasClamp = depthBiasClamp;
+        SlopeScaledDepthBias = slopeScaledDepthBias;
+        DepthClipEnable = depthClipEnable;
+        MultisampleEnable = multisampleEnable;
+        AntialiasedLineEnable = antialiasedLineEnable;
+        ForcedSampleCount = forcedSampleCount;
+        ConservativeRaster = conservativeRaster;
+    }
+
+
+    operator D3D12_RASTERIZER_DESC() const noexcept
+    {
+        D3D12_RASTERIZER_DESC o;
+
+        o.FillMode = FillMode;
+        o.CullMode = CullMode;
+        o.FrontCounterClockwise = FrontCounterClockwise;
+        o.DepthBias = static_cast<INT>(DepthBias);
+        o.DepthBiasClamp = DepthBiasClamp;
+        o.SlopeScaledDepthBias = SlopeScaledDepthBias;
+        o.DepthClipEnable = DepthClipEnable;
+        o.MultisampleEnable = MultisampleEnable;
+        o.AntialiasedLineEnable = AntialiasedLineEnable;
+        o.ForcedSampleCount = ForcedSampleCount;
+        o.ConservativeRaster = ConservativeRaster;
+
+        return o;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 608
+
+//------------------------------------------------------------------------------------------------
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+struct CD3DX12_RASTERIZER_DESC2 : public D3D12_RASTERIZER_DESC2
+{
+    CD3DX12_RASTERIZER_DESC2() = default;
+    explicit CD3DX12_RASTERIZER_DESC2(const D3D12_RASTERIZER_DESC2& o) noexcept :
+        D3D12_RASTERIZER_DESC2(o)
+
+    {
+    }
+    explicit CD3DX12_RASTERIZER_DESC2(const D3D12_RASTERIZER_DESC1& o) noexcept
+    {
+        FillMode = o.FillMode;
+        CullMode = o.CullMode;
+        FrontCounterClockwise = o.FrontCounterClockwise;
+        DepthBias = o.DepthBias;
+        DepthBiasClamp = o.DepthBiasClamp;
+        SlopeScaledDepthBias = o.SlopeScaledDepthBias;
+        DepthClipEnable = o.DepthClipEnable;
+        LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
+        if (o.MultisampleEnable)
+        {
+            LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE;
+        }
+        else if (o.AntialiasedLineEnable)
+        {
+            LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED;
+        }
+        ForcedSampleCount = o.ForcedSampleCount;
+        ConservativeRaster = o.ConservativeRaster;
+    }
+    explicit CD3DX12_RASTERIZER_DESC2(const D3D12_RASTERIZER_DESC& o) noexcept
+        : CD3DX12_RASTERIZER_DESC2(CD3DX12_RASTERIZER_DESC1(o))
+    {
+    }
+    explicit CD3DX12_RASTERIZER_DESC2(CD3DX12_DEFAULT) noexcept
+    {
+        FillMode = D3D12_FILL_MODE_SOLID;
+        CullMode = D3D12_CULL_MODE_BACK;
+        FrontCounterClockwise = FALSE;
+        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+        DepthClipEnable = TRUE;
+        LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
+        ForcedSampleCount = 0;
+        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+    }
+    explicit CD3DX12_RASTERIZER_DESC2(
+        D3D12_FILL_MODE fillMode,
+        D3D12_CULL_MODE cullMode,
+        BOOL frontCounterClockwise,
+        FLOAT depthBias,
+        FLOAT depthBiasClamp,
+        FLOAT slopeScaledDepthBias,
+        BOOL depthClipEnable,
+        D3D12_LINE_RASTERIZATION_MODE lineRasterizationMode,
+        UINT forcedSampleCount,
+        D3D12_CONSERVATIVE_RASTERIZATION_MODE conservativeRaster) noexcept
+    {
+        FillMode = fillMode;
+        CullMode = cullMode;
+        FrontCounterClockwise = frontCounterClockwise;
+        DepthBias = depthBias;
+        DepthBiasClamp = depthBiasClamp;
+        SlopeScaledDepthBias = slopeScaledDepthBias;
+        DepthClipEnable = depthClipEnable;
+        LineRasterizationMode = lineRasterizationMode;
+        ForcedSampleCount = forcedSampleCount;
+        ConservativeRaster = conservativeRaster;
+    }
+
+
+    operator D3D12_RASTERIZER_DESC1() const noexcept
+    {
+        D3D12_RASTERIZER_DESC1 o;
+
+        o.FillMode = FillMode;
+        o.CullMode = CullMode;
+        o.FrontCounterClockwise = FrontCounterClockwise;
+        o.DepthBias = DepthBias;
+        o.DepthBiasClamp = DepthBiasClamp;
+        o.SlopeScaledDepthBias = SlopeScaledDepthBias;
+        o.DepthClipEnable = DepthClipEnable;
+        o.MultisampleEnable = FALSE;
+        o.AntialiasedLineEnable = FALSE;
+        if (LineRasterizationMode == D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED)
+        {
+            o.AntialiasedLineEnable = TRUE;
+        }
+        else if (LineRasterizationMode != D3D12_LINE_RASTERIZATION_MODE_ALIASED)
+        {
+            o.MultisampleEnable = TRUE;
+        }
+        o.ForcedSampleCount = ForcedSampleCount;
+        o.ConservativeRaster = ConservativeRaster;
+
+        return o;
+    }
+    operator D3D12_RASTERIZER_DESC() const noexcept
+    {
+        return (D3D12_RASTERIZER_DESC)CD3DX12_RASTERIZER_DESC1((D3D12_RASTERIZER_DESC1)*this);
+    }
+};
+#endif // D3D12_SDK_VERSION >= 610
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RESOURCE_ALLOCATION_INFO : public D3D12_RESOURCE_ALLOCATION_INFO
+{
+    CD3DX12_RESOURCE_ALLOCATION_INFO() = default;
+    explicit CD3DX12_RESOURCE_ALLOCATION_INFO( const D3D12_RESOURCE_ALLOCATION_INFO& o ) noexcept :
+        D3D12_RESOURCE_ALLOCATION_INFO( o )
+    {}
+    CD3DX12_RESOURCE_ALLOCATION_INFO(
+        UINT64 size,
+        UINT64 alignment ) noexcept
+    {
+        SizeInBytes = size;
+        Alignment = alignment;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_HEAP_PROPERTIES : public D3D12_HEAP_PROPERTIES
+{
+    CD3DX12_HEAP_PROPERTIES() = default;
+    explicit CD3DX12_HEAP_PROPERTIES(const D3D12_HEAP_PROPERTIES &o) noexcept :
+        D3D12_HEAP_PROPERTIES(o)
+    {}
+    CD3DX12_HEAP_PROPERTIES(
+        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
+        D3D12_MEMORY_POOL memoryPoolPreference,
+        UINT creationNodeMask = 1,
+        UINT nodeMask = 1 ) noexcept
+    {
+        Type = D3D12_HEAP_TYPE_CUSTOM;
+        CPUPageProperty = cpuPageProperty;
+        MemoryPoolPreference = memoryPoolPreference;
+        CreationNodeMask = creationNodeMask;
+        VisibleNodeMask = nodeMask;
+    }
+    explicit CD3DX12_HEAP_PROPERTIES(
+        D3D12_HEAP_TYPE type,
+        UINT creationNodeMask = 1,
+        UINT nodeMask = 1 ) noexcept
+    {
+        Type = type;
+        CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+        MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+        CreationNodeMask = creationNodeMask;
+        VisibleNodeMask = nodeMask;
+    }
+    bool IsCPUAccessible() const noexcept
+    {
+        return Type == D3D12_HEAP_TYPE_UPLOAD || Type == D3D12_HEAP_TYPE_READBACK
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+            || Type == D3D12_HEAP_TYPE_GPU_UPLOAD
+#endif
+            || (Type == D3D12_HEAP_TYPE_CUSTOM &&
+                (CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK));
+    }
+};
+inline bool operator==( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept
+{
+    return l.Type == r.Type && l.CPUPageProperty == r.CPUPageProperty &&
+        l.MemoryPoolPreference == r.MemoryPoolPreference &&
+        l.CreationNodeMask == r.CreationNodeMask &&
+        l.VisibleNodeMask == r.VisibleNodeMask;
+}
+inline bool operator!=( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_HEAP_DESC : public D3D12_HEAP_DESC
+{
+    CD3DX12_HEAP_DESC() = default;
+    explicit CD3DX12_HEAP_DESC(const D3D12_HEAP_DESC &o) noexcept :
+        D3D12_HEAP_DESC(o)
+    {}
+    CD3DX12_HEAP_DESC(
+        UINT64 size,
+        D3D12_HEAP_PROPERTIES properties,
+        UINT64 alignment = 0,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = size;
+        Properties = properties;
+        Alignment = alignment;
+        Flags = flags;
+    }
+    CD3DX12_HEAP_DESC(
+        UINT64 size,
+        D3D12_HEAP_TYPE type,
+        UINT64 alignment = 0,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = size;
+        Properties = CD3DX12_HEAP_PROPERTIES( type );
+        Alignment = alignment;
+        Flags = flags;
+    }
+    CD3DX12_HEAP_DESC(
+        UINT64 size,
+        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
+        D3D12_MEMORY_POOL memoryPoolPreference,
+        UINT64 alignment = 0,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = size;
+        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );
+        Alignment = alignment;
+        Flags = flags;
+    }
+    CD3DX12_HEAP_DESC(
+        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
+        D3D12_HEAP_PROPERTIES properties,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = resAllocInfo.SizeInBytes;
+        Properties = properties;
+        Alignment = resAllocInfo.Alignment;
+        Flags = flags;
+    }
+    CD3DX12_HEAP_DESC(
+        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
+        D3D12_HEAP_TYPE type,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = resAllocInfo.SizeInBytes;
+        Properties = CD3DX12_HEAP_PROPERTIES( type );
+        Alignment = resAllocInfo.Alignment;
+        Flags = flags;
+    }
+    CD3DX12_HEAP_DESC(
+        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
+        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,
+        D3D12_MEMORY_POOL memoryPoolPreference,
+        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept
+    {
+        SizeInBytes = resAllocInfo.SizeInBytes;
+        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );
+        Alignment = resAllocInfo.Alignment;
+        Flags = flags;
+    }
+    bool IsCPUAccessible() const noexcept
+    { return static_cast< const CD3DX12_HEAP_PROPERTIES* >( &Properties )->IsCPUAccessible(); }
+};
+inline bool operator==( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept
+{
+    return l.SizeInBytes == r.SizeInBytes &&
+        l.Properties == r.Properties &&
+        l.Alignment == r.Alignment &&
+        l.Flags == r.Flags;
+}
+inline bool operator!=( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_CLEAR_VALUE : public D3D12_CLEAR_VALUE
+{
+    CD3DX12_CLEAR_VALUE() = default;
+    explicit CD3DX12_CLEAR_VALUE(const D3D12_CLEAR_VALUE &o) noexcept :
+        D3D12_CLEAR_VALUE(o)
+    {}
+    CD3DX12_CLEAR_VALUE(
+        DXGI_FORMAT format,
+        const FLOAT color[4] ) noexcept
+    {
+        Format = format;
+        memcpy( Color, color, sizeof( Color ) );
+    }
+    CD3DX12_CLEAR_VALUE(
+        DXGI_FORMAT format,
+        FLOAT depth,
+        UINT8 stencil ) noexcept
+    {
+        Format = format;
+        memset( &Color, 0, sizeof( Color ) );
+        /* Use memcpy to preserve NAN values */
+        memcpy( &DepthStencil.Depth, &depth, sizeof( depth ) );
+        DepthStencil.Stencil = stencil;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+inline bool operator==( const D3D12_CLEAR_VALUE &a, const D3D12_CLEAR_VALUE &b) noexcept
+{
+    if (a.Format != b.Format) return false;
+    if (a.Format == DXGI_FORMAT_D24_UNORM_S8_UINT
+     || a.Format == DXGI_FORMAT_D16_UNORM
+     || a.Format == DXGI_FORMAT_D32_FLOAT
+     || a.Format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
+    {
+        return (a.DepthStencil.Depth == b.DepthStencil.Depth) &&
+          (a.DepthStencil.Stencil == b.DepthStencil.Stencil);
+    } else {
+        return (a.Color[0] == b.Color[0]) &&
+               (a.Color[1] == b.Color[1]) &&
+               (a.Color[2] == b.Color[2]) &&
+               (a.Color[3] == b.Color[3]);
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RANGE : public D3D12_RANGE
+{
+    CD3DX12_RANGE() = default;
+    explicit CD3DX12_RANGE(const D3D12_RANGE &o) noexcept :
+        D3D12_RANGE(o)
+    {}
+    CD3DX12_RANGE(
+        SIZE_T begin,
+        SIZE_T end ) noexcept
+    {
+        Begin = begin;
+        End = end;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RANGE_UINT64 : public D3D12_RANGE_UINT64
+{
+    CD3DX12_RANGE_UINT64() = default;
+    explicit CD3DX12_RANGE_UINT64(const D3D12_RANGE_UINT64 &o) noexcept :
+        D3D12_RANGE_UINT64(o)
+    {}
+    CD3DX12_RANGE_UINT64(
+        UINT64 begin,
+        UINT64 end ) noexcept
+    {
+        Begin = begin;
+        End = end;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_SUBRESOURCE_RANGE_UINT64 : public D3D12_SUBRESOURCE_RANGE_UINT64
+{
+    CD3DX12_SUBRESOURCE_RANGE_UINT64() = default;
+    explicit CD3DX12_SUBRESOURCE_RANGE_UINT64(const D3D12_SUBRESOURCE_RANGE_UINT64 &o) noexcept :
+        D3D12_SUBRESOURCE_RANGE_UINT64(o)
+    {}
+    CD3DX12_SUBRESOURCE_RANGE_UINT64(
+        UINT subresource,
+        const D3D12_RANGE_UINT64& range ) noexcept
+    {
+        Subresource = subresource;
+        Range = range;
+    }
+    CD3DX12_SUBRESOURCE_RANGE_UINT64(
+        UINT subresource,
+        UINT64 begin,
+        UINT64 end ) noexcept
+    {
+        Subresource = subresource;
+        Range.Begin = begin;
+        Range.End = end;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_SHADER_BYTECODE : public D3D12_SHADER_BYTECODE
+{
+    CD3DX12_SHADER_BYTECODE() = default;
+    explicit CD3DX12_SHADER_BYTECODE(const D3D12_SHADER_BYTECODE &o) noexcept :
+        D3D12_SHADER_BYTECODE(o)
+    {}
+    CD3DX12_SHADER_BYTECODE(
+        _In_ ID3DBlob* pShaderBlob ) noexcept
+    {
+        pShaderBytecode = pShaderBlob->GetBufferPointer();
+        BytecodeLength = pShaderBlob->GetBufferSize();
+    }
+    CD3DX12_SHADER_BYTECODE(
+        const void* _pShaderBytecode,
+        SIZE_T bytecodeLength ) noexcept
+    {
+        pShaderBytecode = _pShaderBytecode;
+        BytecodeLength = bytecodeLength;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_TILED_RESOURCE_COORDINATE : public D3D12_TILED_RESOURCE_COORDINATE
+{
+    CD3DX12_TILED_RESOURCE_COORDINATE() = default;
+    explicit CD3DX12_TILED_RESOURCE_COORDINATE(const D3D12_TILED_RESOURCE_COORDINATE &o) noexcept :
+        D3D12_TILED_RESOURCE_COORDINATE(o)
+    {}
+    CD3DX12_TILED_RESOURCE_COORDINATE(
+        UINT x,
+        UINT y,
+        UINT z,
+        UINT subresource ) noexcept
+    {
+        X = x;
+        Y = y;
+        Z = z;
+        Subresource = subresource;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_TILE_REGION_SIZE : public D3D12_TILE_REGION_SIZE
+{
+    CD3DX12_TILE_REGION_SIZE() = default;
+    explicit CD3DX12_TILE_REGION_SIZE(const D3D12_TILE_REGION_SIZE &o) noexcept :
+        D3D12_TILE_REGION_SIZE(o)
+    {}
+    CD3DX12_TILE_REGION_SIZE(
+        UINT numTiles,
+        BOOL useBox,
+        UINT width,
+        UINT16 height,
+        UINT16 depth ) noexcept
+    {
+        NumTiles = numTiles;
+        UseBox = useBox;
+        Width = width;
+        Height = height;
+        Depth = depth;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_SUBRESOURCE_TILING : public D3D12_SUBRESOURCE_TILING
+{
+    CD3DX12_SUBRESOURCE_TILING() = default;
+    explicit CD3DX12_SUBRESOURCE_TILING(const D3D12_SUBRESOURCE_TILING &o) noexcept :
+        D3D12_SUBRESOURCE_TILING(o)
+    {}
+    CD3DX12_SUBRESOURCE_TILING(
+        UINT widthInTiles,
+        UINT16 heightInTiles,
+        UINT16 depthInTiles,
+        UINT startTileIndexInOverallResource ) noexcept
+    {
+        WidthInTiles = widthInTiles;
+        HeightInTiles = heightInTiles;
+        DepthInTiles = depthInTiles;
+        StartTileIndexInOverallResource = startTileIndexInOverallResource;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_TILE_SHAPE : public D3D12_TILE_SHAPE
+{
+    CD3DX12_TILE_SHAPE() = default;
+    explicit CD3DX12_TILE_SHAPE(const D3D12_TILE_SHAPE &o) noexcept :
+        D3D12_TILE_SHAPE(o)
+    {}
+    CD3DX12_TILE_SHAPE(
+        UINT widthInTexels,
+        UINT heightInTexels,
+        UINT depthInTexels ) noexcept
+    {
+        WidthInTexels = widthInTexels;
+        HeightInTexels = heightInTexels;
+        DepthInTexels = depthInTexels;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_PACKED_MIP_INFO : public D3D12_PACKED_MIP_INFO
+{
+    CD3DX12_PACKED_MIP_INFO() = default;
+    explicit CD3DX12_PACKED_MIP_INFO(const D3D12_PACKED_MIP_INFO &o) noexcept :
+        D3D12_PACKED_MIP_INFO(o)
+    {}
+    CD3DX12_PACKED_MIP_INFO(
+        UINT8 numStandardMips,
+        UINT8 numPackedMips,
+        UINT numTilesForPackedMips,
+        UINT startTileIndexInOverallResource ) noexcept
+    {
+        NumStandardMips = numStandardMips;
+        NumPackedMips = numPackedMips;
+        NumTilesForPackedMips = numTilesForPackedMips;
+        StartTileIndexInOverallResource = startTileIndexInOverallResource;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_SUBRESOURCE_FOOTPRINT : public D3D12_SUBRESOURCE_FOOTPRINT
+{
+    CD3DX12_SUBRESOURCE_FOOTPRINT() = default;
+    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(const D3D12_SUBRESOURCE_FOOTPRINT &o) noexcept :
+        D3D12_SUBRESOURCE_FOOTPRINT(o)
+    {}
+    CD3DX12_SUBRESOURCE_FOOTPRINT(
+        DXGI_FORMAT format,
+        UINT width,
+        UINT height,
+        UINT depth,
+        UINT rowPitch ) noexcept
+    {
+        Format = format;
+        Width = width;
+        Height = height;
+        Depth = depth;
+        RowPitch = rowPitch;
+    }
+    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(
+        const D3D12_RESOURCE_DESC& resDesc,
+        UINT rowPitch ) noexcept
+    {
+        Format = resDesc.Format;
+        Width = UINT( resDesc.Width );
+        Height = resDesc.Height;
+        Depth = (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? resDesc.DepthOrArraySize : 1u);
+        RowPitch = rowPitch;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_TEXTURE_COPY_LOCATION : public D3D12_TEXTURE_COPY_LOCATION
+{
+    CD3DX12_TEXTURE_COPY_LOCATION() = default;
+    explicit CD3DX12_TEXTURE_COPY_LOCATION(const D3D12_TEXTURE_COPY_LOCATION &o) noexcept :
+        D3D12_TEXTURE_COPY_LOCATION(o)
+    {}
+    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes) noexcept
+    {
+        pResource = pRes;
+        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+        PlacedFootprint = {};
+    }
+    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, D3D12_PLACED_SUBRESOURCE_FOOTPRINT const& Footprint) noexcept
+    {
+        pResource = pRes;
+        Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+        PlacedFootprint = Footprint;
+    }
+    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, UINT Sub) noexcept
+    {
+        pResource = pRes;
+        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+        PlacedFootprint = {};
+        SubresourceIndex = Sub;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+constexpr UINT D3D12CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize ) noexcept
+{
+    return MipSlice + ArraySlice * MipLevels + PlaneSlice * MipLevels * ArraySize;
+}
+
+//------------------------------------------------------------------------------------------------
+inline UINT8 D3D12GetFormatPlaneCount(
+    _In_ ID3D12Device* pDevice,
+    DXGI_FORMAT Format
+    ) noexcept
+{
+    D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { Format, 0 };
+    if (FAILED(pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))
+    {
+        return 0;
+    }
+    return formatInfo.PlaneCount;
+}
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RESOURCE_DESC : public D3D12_RESOURCE_DESC
+{
+    CD3DX12_RESOURCE_DESC() = default;
+    explicit CD3DX12_RESOURCE_DESC( const D3D12_RESOURCE_DESC& o ) noexcept :
+        D3D12_RESOURCE_DESC( o )
+    {}
+    CD3DX12_RESOURCE_DESC(
+        D3D12_RESOURCE_DIMENSION dimension,
+        UINT64 alignment,
+        UINT64 width,
+        UINT height,
+        UINT16 depthOrArraySize,
+        UINT16 mipLevels,
+        DXGI_FORMAT format,
+        UINT sampleCount,
+        UINT sampleQuality,
+        D3D12_TEXTURE_LAYOUT layout,
+        D3D12_RESOURCE_FLAGS flags ) noexcept
+    {
+        Dimension = dimension;
+        Alignment = alignment;
+        Width = width;
+        Height = height;
+        DepthOrArraySize = depthOrArraySize;
+        MipLevels = mipLevels;
+        Format = format;
+        SampleDesc.Count = sampleCount;
+        SampleDesc.Quality = sampleQuality;
+        Layout = layout;
+        Flags = flags;
+    }
+    static inline CD3DX12_RESOURCE_DESC Buffer(
+        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,
+            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );
+    }
+    static inline CD3DX12_RESOURCE_DESC Buffer(
+        UINT64 width,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,
+            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );
+    }
+    static inline CD3DX12_RESOURCE_DESC Tex1D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT16 arraySize = 1,
+        UINT16 mipLevels = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,
+            mipLevels, format, 1, 0, layout, flags );
+    }
+    static inline CD3DX12_RESOURCE_DESC Tex2D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT height,
+        UINT16 arraySize = 1,
+        UINT16 mipLevels = 0,
+        UINT sampleCount = 1,
+        UINT sampleQuality = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,
+            mipLevels, format, sampleCount, sampleQuality, layout, flags );
+    }
+    static inline CD3DX12_RESOURCE_DESC Tex3D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT height,
+        UINT16 depth,
+        UINT16 mipLevels = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,
+            mipLevels, format, 1, 0, layout, flags );
+    }
+    inline UINT16 Depth() const noexcept
+    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
+    inline UINT16 ArraySize() const noexcept
+    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
+    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept
+    { return D3D12GetFormatPlaneCount(pDevice, Format); }
+    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept
+    { return static_cast<UINT>(MipLevels) * ArraySize() * PlaneCount(pDevice); }
+    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept
+    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }
+};
+inline bool operator==( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept
+{
+    return l.Dimension == r.Dimension &&
+        l.Alignment == r.Alignment &&
+        l.Width == r.Width &&
+        l.Height == r.Height &&
+        l.DepthOrArraySize == r.DepthOrArraySize &&
+        l.MipLevels == r.MipLevels &&
+        l.Format == r.Format &&
+        l.SampleDesc.Count == r.SampleDesc.Count &&
+        l.SampleDesc.Quality == r.SampleDesc.Quality &&
+        l.Layout == r.Layout &&
+        l.Flags == r.Flags;
+}
+inline bool operator!=( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RESOURCE_DESC1 : public D3D12_RESOURCE_DESC1
+{
+    CD3DX12_RESOURCE_DESC1() = default;
+    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC1& o ) noexcept :
+        D3D12_RESOURCE_DESC1( o )
+    {}
+    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC& o ) noexcept
+    {
+        Dimension = o.Dimension;
+        Alignment = o.Alignment;
+        Width = o.Width;
+        Height = o.Height;
+        DepthOrArraySize = o.DepthOrArraySize;
+        MipLevels = o.MipLevels;
+        Format = o.Format;
+        SampleDesc = o.SampleDesc;
+        Layout = o.Layout;
+        Flags = o.Flags;
+        SamplerFeedbackMipRegion = {};
+    }
+    CD3DX12_RESOURCE_DESC1(
+        D3D12_RESOURCE_DIMENSION dimension,
+        UINT64 alignment,
+        UINT64 width,
+        UINT height,
+        UINT16 depthOrArraySize,
+        UINT16 mipLevels,
+        DXGI_FORMAT format,
+        UINT sampleCount,
+        UINT sampleQuality,
+        D3D12_TEXTURE_LAYOUT layout,
+        D3D12_RESOURCE_FLAGS flags,
+        UINT samplerFeedbackMipRegionWidth = 0,
+        UINT samplerFeedbackMipRegionHeight = 0,
+        UINT samplerFeedbackMipRegionDepth = 0) noexcept
+    {
+        Dimension = dimension;
+        Alignment = alignment;
+        Width = width;
+        Height = height;
+        DepthOrArraySize = depthOrArraySize;
+        MipLevels = mipLevels;
+        Format = format;
+        SampleDesc.Count = sampleCount;
+        SampleDesc.Quality = sampleQuality;
+        Layout = layout;
+        Flags = flags;
+        SamplerFeedbackMipRegion.Width = samplerFeedbackMipRegionWidth;
+        SamplerFeedbackMipRegion.Height = samplerFeedbackMipRegionHeight;
+        SamplerFeedbackMipRegion.Depth = samplerFeedbackMipRegionDepth;
+    }
+
+    static inline CD3DX12_RESOURCE_DESC1 Buffer(
+        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,
+            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );
+    }
+    static inline CD3DX12_RESOURCE_DESC1 Buffer(
+        UINT64 width,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,
+            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );
+    }
+    static inline CD3DX12_RESOURCE_DESC1 Tex1D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT16 arraySize = 1,
+        UINT16 mipLevels = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,
+            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );
+    }
+    static inline CD3DX12_RESOURCE_DESC1 Tex2D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT height,
+        UINT16 arraySize = 1,
+        UINT16 mipLevels = 0,
+        UINT sampleCount = 1,
+        UINT sampleQuality = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0,
+        UINT samplerFeedbackMipRegionWidth = 0,
+        UINT samplerFeedbackMipRegionHeight = 0,
+        UINT samplerFeedbackMipRegionDepth = 0) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,
+            mipLevels, format, sampleCount, sampleQuality, layout, flags, samplerFeedbackMipRegionWidth,
+            samplerFeedbackMipRegionHeight, samplerFeedbackMipRegionDepth );
+    }
+    static inline CD3DX12_RESOURCE_DESC1 Tex3D(
+        DXGI_FORMAT format,
+        UINT64 width,
+        UINT height,
+        UINT16 depth,
+        UINT16 mipLevels = 0,
+        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
+        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        UINT64 alignment = 0 ) noexcept
+    {
+        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,
+            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );
+    }
+    inline UINT16 Depth() const noexcept
+    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
+    inline UINT16 ArraySize() const noexcept
+    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1u); }
+    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept
+    { return D3D12GetFormatPlaneCount(pDevice, Format); }
+    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept
+    { return static_cast<UINT>(MipLevels) * ArraySize() * PlaneCount(pDevice); }
+    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept
+    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }
+};
+inline bool operator==( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept
+{
+    return l.Dimension == r.Dimension &&
+        l.Alignment == r.Alignment &&
+        l.Width == r.Width &&
+        l.Height == r.Height &&
+        l.DepthOrArraySize == r.DepthOrArraySize &&
+        l.MipLevels == r.MipLevels &&
+        l.Format == r.Format &&
+        l.SampleDesc.Count == r.SampleDesc.Count &&
+        l.SampleDesc.Quality == r.SampleDesc.Quality &&
+        l.Layout == r.Layout &&
+        l.Flags == r.Flags &&
+        l.SamplerFeedbackMipRegion.Width == r.SamplerFeedbackMipRegion.Width &&
+        l.SamplerFeedbackMipRegion.Height == r.SamplerFeedbackMipRegion.Height &&
+        l.SamplerFeedbackMipRegion.Depth == r.SamplerFeedbackMipRegion.Depth;
+}
+inline bool operator!=( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept
+{ return !( l == r ); }
+
+//------------------------------------------------------------------------------------------------
+// Fills in the mipmap and alignment values of pDesc when either members are zero
+// Used to replace an implicit field to an explicit (0 mip map = max mip map level)
+// If expansion has occured, returns LclDesc, else returns the original pDesc
+inline const CD3DX12_RESOURCE_DESC1* D3DX12ConditionallyExpandAPIDesc(
+    CD3DX12_RESOURCE_DESC1& LclDesc,
+    const CD3DX12_RESOURCE_DESC1* pDesc)
+{
+    // Expand mip levels:
+    if (pDesc->MipLevels == 0 || pDesc->Alignment == 0)
+    {
+        LclDesc = *pDesc;
+        if (pDesc->MipLevels == 0)
+        {
+            auto MaxMipLevels = [](UINT64 uiMaxDimension) -> UINT16
+            {
+                UINT16 uiRet = 0;
+                while (uiMaxDimension > 0)
+                {
+                    uiRet++;
+                    uiMaxDimension >>= 1;
+                }
+                return uiRet;
+            };
+            auto Max = [](UINT64 const & a, UINT64 const & b)
+            {
+                return (a < b) ? b : a;
+            };
+
+            LclDesc.MipLevels = MaxMipLevels(
+                Max(LclDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? LclDesc.DepthOrArraySize : 1,
+                    Max(LclDesc.Width, LclDesc.Height)));
+        }
+        if (pDesc->Alignment == 0)
+        {
+            if (pDesc->Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE
+                || pDesc->Layout == D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE
+                )
+            {
+                LclDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+            }
+            else
+            {
+                LclDesc.Alignment =
+                    (pDesc->SampleDesc.Count > 1 ? D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
+            }
+        }
+        return &LclDesc;
+    }
+    else
+    {
+        return pDesc;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_VIEW_INSTANCING_DESC : public D3D12_VIEW_INSTANCING_DESC
+{
+    CD3DX12_VIEW_INSTANCING_DESC() = default;
+    explicit CD3DX12_VIEW_INSTANCING_DESC( const D3D12_VIEW_INSTANCING_DESC& o ) noexcept :
+        D3D12_VIEW_INSTANCING_DESC( o )
+    {}
+    explicit CD3DX12_VIEW_INSTANCING_DESC( CD3DX12_DEFAULT ) noexcept
+    {
+        ViewInstanceCount = 0;
+        pViewInstanceLocations = nullptr;
+        Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
+    }
+    explicit CD3DX12_VIEW_INSTANCING_DESC(
+        UINT InViewInstanceCount,
+        const D3D12_VIEW_INSTANCE_LOCATION* InViewInstanceLocations,
+        D3D12_VIEW_INSTANCING_FLAGS InFlags) noexcept
+    {
+        ViewInstanceCount = InViewInstanceCount;
+        pViewInstanceLocations = InViewInstanceLocations;
+        Flags = InFlags;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_RT_FORMAT_ARRAY : public D3D12_RT_FORMAT_ARRAY
+{
+    CD3DX12_RT_FORMAT_ARRAY() = default;
+    explicit CD3DX12_RT_FORMAT_ARRAY(const D3D12_RT_FORMAT_ARRAY& o) noexcept
+        : D3D12_RT_FORMAT_ARRAY(o)
+    {}
+    explicit CD3DX12_RT_FORMAT_ARRAY(_In_reads_(NumFormats) const DXGI_FORMAT* pFormats, UINT NumFormats) noexcept
+    {
+        NumRenderTargets = NumFormats;
+        memcpy(RTFormats, pFormats, sizeof(RTFormats));
+        // assumes ARRAY_SIZE(pFormats) == ARRAY_SIZE(RTFormats)
+    }
+};

+ 12 - 0
thirdparty/directx_headers/include/directx/d3dx12_default.h

@@ -0,0 +1,12 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+struct CD3DX12_DEFAULT {};
+extern const DECLSPEC_SELECTANY CD3DX12_DEFAULT D3D12_DEFAULT;
+

+ 1411 - 0
thirdparty/directx_headers/include/directx/d3dx12_pipeline_state_stream.h

@@ -0,0 +1,1411 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+#include "d3dx12_default.h"
+#include "d3dx12_core.h"
+
+//------------------------------------------------------------------------------------------------
+// Pipeline State Stream Helpers
+//------------------------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------------------------
+// Stream Subobjects, i.e. elements of a stream
+
+struct DefaultSampleMask { operator UINT() noexcept { return UINT_MAX; } };
+struct DefaultSampleDesc { operator DXGI_SAMPLE_DESC() noexcept { return DXGI_SAMPLE_DESC{1, 0}; } };
+
+/* GODOT start */
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4324)
+#endif
+/* GODOT start */
+template <typename InnerStructType, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type, typename DefaultArg = InnerStructType>
+class alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT
+{
+private:
+    D3D12_PIPELINE_STATE_SUBOBJECT_TYPE pssType;
+    InnerStructType pssInner;
+public:
+    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT() noexcept : pssType(Type), pssInner(DefaultArg()) {}
+    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT(InnerStructType const& i) noexcept : pssType(Type), pssInner(i) {}
+    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT& operator=(InnerStructType const& i) noexcept { pssType = Type; pssInner = i; return *this; }
+    operator InnerStructType const&() const noexcept { return pssInner; }
+    operator InnerStructType&() noexcept { return pssInner; }
+    InnerStructType* operator&() noexcept { return &pssInner; }
+    InnerStructType const* operator&() const noexcept { return &pssInner; }
+};
+/* GODOT start */
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+/* GODOT end */
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PIPELINE_STATE_FLAGS,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS>                             CD3DX12_PIPELINE_STATE_STREAM_FLAGS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK>                         CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< ID3D12RootSignature*,               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE>                    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INPUT_LAYOUT_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT>                      CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE>                CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PRIMITIVE_TOPOLOGY_TYPE,      D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY>                CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS>                                CD3DX12_PIPELINE_STATE_STREAM_VS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS>                                CD3DX12_PIPELINE_STATE_STREAM_GS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_STREAM_OUTPUT_DESC,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT>                     CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS>                                CD3DX12_PIPELINE_STATE_STREAM_HS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS>                                CD3DX12_PIPELINE_STATE_STREAM_DS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS>                                CD3DX12_PIPELINE_STATE_STREAM_PS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS>                                CD3DX12_PIPELINE_STATE_STREAM_AS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS>                                CD3DX12_PIPELINE_STATE_STREAM_MS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS>                                CD3DX12_PIPELINE_STATE_STREAM_CS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_BLEND_DESC,                 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,          CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,  CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC1,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC2,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2;
+#endif
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_FORMAT,                        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT>              CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,     CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC1,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1,    CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER1;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC2,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2,    CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER2;
+#endif
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_RT_FORMAT_ARRAY,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS>             CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_SAMPLE_DESC,                   D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,    DefaultSampleDesc> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,    DefaultSampleMask> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_CACHED_PIPELINE_STATE,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO>                        CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO;
+typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_VIEW_INSTANCING_DESC,       D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, CD3DX12_DEFAULT>  CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING;
+
+//------------------------------------------------------------------------------------------------
+// Stream Parser Helpers
+
+struct ID3DX12PipelineParserCallbacks
+{
+    // Subobject Callbacks
+    virtual void FlagsCb(D3D12_PIPELINE_STATE_FLAGS) {}
+    virtual void NodeMaskCb(UINT) {}
+    virtual void RootSignatureCb(ID3D12RootSignature*) {}
+    virtual void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC&) {}
+    virtual void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE) {}
+    virtual void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE) {}
+    virtual void VSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void GSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC&) {}
+    virtual void HSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void DSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void PSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void CSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void ASCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void MSCb(const D3D12_SHADER_BYTECODE&) {}
+    virtual void BlendStateCb(const D3D12_BLEND_DESC&) {}
+    virtual void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC&) {}
+    virtual void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1&) {}
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+    virtual void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2&) {}
+#endif
+    virtual void DSVFormatCb(DXGI_FORMAT) {}
+    virtual void RasterizerStateCb(const D3D12_RASTERIZER_DESC&) {}
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+    virtual void RasterizerState1Cb(const D3D12_RASTERIZER_DESC1&) {}
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+    virtual void RasterizerState2Cb(const D3D12_RASTERIZER_DESC2&) {}
+#endif
+    virtual void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY&) {}
+    virtual void SampleDescCb(const DXGI_SAMPLE_DESC&) {}
+    virtual void SampleMaskCb(UINT) {}
+    virtual void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC&) {}
+    virtual void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE&) {}
+
+    // Error Callbacks
+    virtual void ErrorBadInputParameter(UINT /*ParameterIndex*/) {}
+    virtual void ErrorDuplicateSubobject(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE /*DuplicateType*/) {}
+    virtual void ErrorUnknownSubobject(UINT /*UnknownTypeValue*/) {}
+
+    virtual ~ID3DX12PipelineParserCallbacks() = default;
+};
+
+struct D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
+{
+    ID3D12RootSignature*          pRootSignature;
+    D3D12_SHADER_BYTECODE         AS;
+    D3D12_SHADER_BYTECODE         MS;
+    D3D12_SHADER_BYTECODE         PS;
+    D3D12_BLEND_DESC              BlendState;
+    UINT                          SampleMask;
+    D3D12_RASTERIZER_DESC         RasterizerState;
+    D3D12_DEPTH_STENCIL_DESC      DepthStencilState;
+    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;
+};
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+// Use CD3DX12_PIPELINE_STATE_STREAM5 for D3D12_RASTERIZER_DESC2 when CheckFeatureSupport returns true for Options19::RasterizerDesc2Supported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM4 for D3D12_RASTERIZER_DESC1 when CheckFeatureSupport returns true for Options16::DynamicDepthBiasSupported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM3 for D3D12_DEPTH_STENCIL_DESC2 when CheckFeatureSupport returns true for Options14::IndependentFrontAndBackStencilSupported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM2 for OS Build 19041+ (where there is a new mesh shader pipeline).
+// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
+// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
+struct CD3DX12_PIPELINE_STATE_STREAM5
+{
+    CD3DX12_PIPELINE_STATE_STREAM5() = default;
+    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
+    CD3DX12_PIPELINE_STATE_STREAM5(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC2(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM5(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , PS(Desc.PS)
+        , AS(Desc.AS)
+        , MS(Desc.MS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC2(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM5(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(DepthStencilState).DepthEnable = false;
+    }
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
+    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER2 RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC2(D3D12_DEPTH_STENCIL_DESC2(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = CD3DX12_RASTERIZER_DESC2(D3D12_RASTERIZER_DESC2(this->RasterizerState));
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 610
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+// Use CD3DX12_PIPELINE_STATE_STREAM4 for D3D12_RASTERIZER_DESC1 when CheckFeatureSupport returns true for Options16::DynamicDepthBiasSupported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM3 for D3D12_DEPTH_STENCIL_DESC2 when CheckFeatureSupport returns true for Options14::IndependentFrontAndBackStencilSupported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM2 for OS Build 19041+ (where there is a new mesh shader pipeline).
+// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
+// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
+struct CD3DX12_PIPELINE_STATE_STREAM4
+{
+    CD3DX12_PIPELINE_STATE_STREAM4() = default;
+    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
+    CD3DX12_PIPELINE_STATE_STREAM4(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC1(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM4(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , PS(Desc.PS)
+        , AS(Desc.AS)
+        , MS(Desc.MS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC1(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM4(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(DepthStencilState).DepthEnable = false;
+    }
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
+    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER1 RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC2(D3D12_DEPTH_STENCIL_DESC2(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = CD3DX12_RASTERIZER_DESC1(D3D12_RASTERIZER_DESC1(this->RasterizerState));
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 608
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+// Use CD3DX12_PIPELINE_STATE_STREAM3 for D3D12_DEPTH_STENCIL_DESC2 when CheckFeatureSupport returns true for Options14::IndependentFrontAndBackStencilSupported is true
+// Use CD3DX12_PIPELINE_STATE_STREAM2 for OS Build 19041+ (where there is a new mesh shader pipeline).
+// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
+// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
+struct CD3DX12_PIPELINE_STATE_STREAM3
+{
+    CD3DX12_PIPELINE_STATE_STREAM3() = default;
+    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
+    CD3DX12_PIPELINE_STATE_STREAM3(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM3(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , PS(Desc.PS)
+        , AS(Desc.AS)
+        , MS(Desc.MS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC2(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM3(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(DepthStencilState).DepthEnable = false;
+    }
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
+    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL2 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC2(D3D12_DEPTH_STENCIL_DESC2(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = this->RasterizerState;
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+#endif // D3D12_SDK_VERSION >= 606
+
+// CD3DX12_PIPELINE_STATE_STREAM2 Works on OS Build 19041+ (where there is a new mesh shader pipeline).
+// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).
+// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
+struct CD3DX12_PIPELINE_STATE_STREAM2
+{
+    CD3DX12_PIPELINE_STATE_STREAM2() = default;
+    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
+    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM2(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , PS(Desc.PS)
+        , AS(Desc.AS)
+        , MS(Desc.MS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {
+        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;
+    }
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
+    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = this->RasterizerState;
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+
+// CD3DX12_PIPELINE_STATE_STREAM1 Works on OS Build 16299+ (where there is a new view instancing subobject).
+// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.
+struct CD3DX12_PIPELINE_STATE_STREAM1
+{
+    CD3DX12_PIPELINE_STATE_STREAM1() = default;
+    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC
+    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM1(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {
+        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;
+    }
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = this->RasterizerState;
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+
+
+struct CD3DX12_PIPELINE_MESH_STATE_STREAM
+{
+    CD3DX12_PIPELINE_MESH_STATE_STREAM() = default;
+    CD3DX12_PIPELINE_MESH_STATE_STREAM(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , PS(Desc.PS)
+        , AS(Desc.AS)
+        , MS(Desc.MS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_AS AS;
+    CD3DX12_PIPELINE_STATE_STREAM_MS MS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;
+    D3DX12_MESH_SHADER_PIPELINE_STATE_DESC MeshShaderDescV0() const noexcept
+    {
+        D3DX12_MESH_SHADER_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.PS                    = this->PS;
+        D.AS                    = this->AS;
+        D.MS                    = this->MS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = this->RasterizerState;
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+
+// CD3DX12_PIPELINE_STATE_STREAM works on OS Build 15063+ but does not support new subobject(s) added in OS Build 16299+.
+// See CD3DX12_PIPELINE_STATE_STREAM1 for instance.
+struct CD3DX12_PIPELINE_STATE_STREAM
+{
+    CD3DX12_PIPELINE_STATE_STREAM() = default;
+    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , InputLayout(Desc.InputLayout)
+        , IBStripCutValue(Desc.IBStripCutValue)
+        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)
+        , VS(Desc.VS)
+        , GS(Desc.GS)
+        , StreamOutput(Desc.StreamOutput)
+        , HS(Desc.HS)
+        , DS(Desc.DS)
+        , PS(Desc.PS)
+        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))
+        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))
+        , DSVFormat(Desc.DSVFormat)
+        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))
+        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))
+        , SampleDesc(Desc.SampleDesc)
+        , SampleMask(Desc.SampleMask)
+        , CachedPSO(Desc.CachedPSO)
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept
+        : Flags(Desc.Flags)
+        , NodeMask(Desc.NodeMask)
+        , pRootSignature(Desc.pRootSignature)
+        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))
+        , CachedPSO(Desc.CachedPSO)
+    {}
+    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;
+    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;
+    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;
+    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;
+    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;
+    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;
+    CD3DX12_PIPELINE_STATE_STREAM_VS VS;
+    CD3DX12_PIPELINE_STATE_STREAM_GS GS;
+    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;
+    CD3DX12_PIPELINE_STATE_STREAM_HS HS;
+    CD3DX12_PIPELINE_STATE_STREAM_DS DS;
+    CD3DX12_PIPELINE_STATE_STREAM_PS PS;
+    CD3DX12_PIPELINE_STATE_STREAM_CS CS;
+    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;
+    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;
+    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;
+    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;
+    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;
+    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept
+    {
+        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.InputLayout           = this->InputLayout;
+        D.IBStripCutValue       = this->IBStripCutValue;
+        D.PrimitiveTopologyType = this->PrimitiveTopologyType;
+        D.VS                    = this->VS;
+        D.GS                    = this->GS;
+        D.StreamOutput          = this->StreamOutput;
+        D.HS                    = this->HS;
+        D.DS                    = this->DS;
+        D.PS                    = this->PS;
+        D.BlendState            = this->BlendState;
+        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));
+        D.DSVFormat             = this->DSVFormat;
+        D.RasterizerState       = this->RasterizerState;
+        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;
+        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));
+        D.SampleDesc            = this->SampleDesc;
+        D.SampleMask            = this->SampleMask;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept
+    {
+        D3D12_COMPUTE_PIPELINE_STATE_DESC D;
+        D.Flags                 = this->Flags;
+        D.NodeMask              = this->NodeMask;
+        D.pRootSignature        = this->pRootSignature;
+        D.CS                    = this->CS;
+        D.CachedPSO             = this->CachedPSO;
+        return D;
+    }
+};
+
+struct CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
+{
+    CD3DX12_PIPELINE_STATE_STREAM2 PipelineStream;
+    CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER() noexcept
+        : SeenDSS(false)
+    {
+        // Adjust defaults to account for absent members.
+        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+        // Depth disabled if no DSV format specified.
+        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;
+    }
+
+    // ID3DX12PipelineParserCallbacks
+    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}
+    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}
+    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}
+    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}
+    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}
+    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}
+    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}
+    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}
+    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}
+    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}
+    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}
+    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}
+    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}
+    void ASCb(const D3D12_SHADER_BYTECODE& AS) override {PipelineStream.AS = AS;}
+    void MSCb(const D3D12_SHADER_BYTECODE& MS) override {PipelineStream.MS = MS;}
+    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}
+    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
+    {
+        PipelineStream.DSVFormat = DSVFormat;
+        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
+        {
+            // Re-enable depth for the default state.
+            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;
+        }
+    }
+    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}
+    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}
+    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}
+    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}
+    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}
+    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}
+
+private:
+    bool SeenDSS;
+};
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+struct CD3DX12_PIPELINE_STATE_STREAM3_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
+{
+    CD3DX12_PIPELINE_STATE_STREAM3 PipelineStream;
+    CD3DX12_PIPELINE_STATE_STREAM3_PARSE_HELPER() noexcept
+        : SeenDSS(false)
+    {
+        // Adjust defaults to account for absent members.
+        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+        // Depth disabled if no DSV format specified.
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = false;
+    }
+
+    // ID3DX12PipelineParserCallbacks
+    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override { PipelineStream.Flags = Flags; }
+    void NodeMaskCb(UINT NodeMask) override { PipelineStream.NodeMask = NodeMask; }
+    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override { PipelineStream.pRootSignature = pRootSignature; }
+    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override { PipelineStream.InputLayout = InputLayout; }
+    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override { PipelineStream.IBStripCutValue = IBStripCutValue; }
+    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override { PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType; }
+    void VSCb(const D3D12_SHADER_BYTECODE& VS) override { PipelineStream.VS = VS; }
+    void GSCb(const D3D12_SHADER_BYTECODE& GS) override { PipelineStream.GS = GS; }
+    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override { PipelineStream.StreamOutput = StreamOutput; }
+    void HSCb(const D3D12_SHADER_BYTECODE& HS) override { PipelineStream.HS = HS; }
+    void DSCb(const D3D12_SHADER_BYTECODE& DS) override { PipelineStream.DS = DS; }
+    void PSCb(const D3D12_SHADER_BYTECODE& PS) override { PipelineStream.PS = PS; }
+    void CSCb(const D3D12_SHADER_BYTECODE& CS) override { PipelineStream.CS = CS; }
+    void ASCb(const D3D12_SHADER_BYTECODE& AS) override { PipelineStream.AS = AS; }
+    void MSCb(const D3D12_SHADER_BYTECODE& MS) override { PipelineStream.MS = MS; }
+    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override { PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState); }
+    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
+    {
+        PipelineStream.DSVFormat = DSVFormat;
+        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
+        {
+            // Re-enable depth for the default state.
+            static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = true;
+        }
+    }
+    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState); }
+    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override { PipelineStream.RTVFormats = RTVFormats; }
+    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override { PipelineStream.SampleDesc = SampleDesc; }
+    void SampleMaskCb(UINT SampleMask) override { PipelineStream.SampleMask = SampleMask; }
+    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override { PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc); }
+    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override { PipelineStream.CachedPSO = CachedPSO; }
+
+private:
+    bool SeenDSS;
+};
+#endif // D3D12_SDK_VERSION >= 606
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+struct CD3DX12_PIPELINE_STATE_STREAM4_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
+{
+    CD3DX12_PIPELINE_STATE_STREAM4 PipelineStream;
+    CD3DX12_PIPELINE_STATE_STREAM4_PARSE_HELPER() noexcept
+        : SeenDSS(false)
+    {
+        // Adjust defaults to account for absent members.
+        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+        // Depth disabled if no DSV format specified.
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = false;
+    }
+
+    // ID3DX12PipelineParserCallbacks
+    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override { PipelineStream.Flags = Flags; }
+    void NodeMaskCb(UINT NodeMask) override { PipelineStream.NodeMask = NodeMask; }
+    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override { PipelineStream.pRootSignature = pRootSignature; }
+    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override { PipelineStream.InputLayout = InputLayout; }
+    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override { PipelineStream.IBStripCutValue = IBStripCutValue; }
+    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override { PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType; }
+    void VSCb(const D3D12_SHADER_BYTECODE& VS) override { PipelineStream.VS = VS; }
+    void GSCb(const D3D12_SHADER_BYTECODE& GS) override { PipelineStream.GS = GS; }
+    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override { PipelineStream.StreamOutput = StreamOutput; }
+    void HSCb(const D3D12_SHADER_BYTECODE& HS) override { PipelineStream.HS = HS; }
+    void DSCb(const D3D12_SHADER_BYTECODE& DS) override { PipelineStream.DS = DS; }
+    void PSCb(const D3D12_SHADER_BYTECODE& PS) override { PipelineStream.PS = PS; }
+    void CSCb(const D3D12_SHADER_BYTECODE& CS) override { PipelineStream.CS = CS; }
+    void ASCb(const D3D12_SHADER_BYTECODE& AS) override { PipelineStream.AS = AS; }
+    void MSCb(const D3D12_SHADER_BYTECODE& MS) override { PipelineStream.MS = MS; }
+    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override { PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState); }
+    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
+    {
+        PipelineStream.DSVFormat = DSVFormat;
+        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
+        {
+            // Re-enable depth for the default state.
+            static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = true;
+        }
+    }
+    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC1(RasterizerState); }
+    void RasterizerState1Cb(const D3D12_RASTERIZER_DESC1& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC1(RasterizerState); }
+    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override { PipelineStream.RTVFormats = RTVFormats; }
+    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override { PipelineStream.SampleDesc = SampleDesc; }
+    void SampleMaskCb(UINT SampleMask) override { PipelineStream.SampleMask = SampleMask; }
+    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override { PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc); }
+    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override { PipelineStream.CachedPSO = CachedPSO; }
+
+private:
+    bool SeenDSS;
+};
+#endif // D3D12_SDK_VERSION >= 608
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+struct CD3DX12_PIPELINE_STATE_STREAM5_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
+{
+    CD3DX12_PIPELINE_STATE_STREAM5 PipelineStream;
+    CD3DX12_PIPELINE_STATE_STREAM5_PARSE_HELPER() noexcept
+        : SeenDSS(false)
+    {
+        // Adjust defaults to account for absent members.
+        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+        // Depth disabled if no DSV format specified.
+        static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = false;
+    }
+
+    // ID3DX12PipelineParserCallbacks
+    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override { PipelineStream.Flags = Flags; }
+    void NodeMaskCb(UINT NodeMask) override { PipelineStream.NodeMask = NodeMask; }
+    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override { PipelineStream.pRootSignature = pRootSignature; }
+    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override { PipelineStream.InputLayout = InputLayout; }
+    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override { PipelineStream.IBStripCutValue = IBStripCutValue; }
+    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override { PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType; }
+    void VSCb(const D3D12_SHADER_BYTECODE& VS) override { PipelineStream.VS = VS; }
+    void GSCb(const D3D12_SHADER_BYTECODE& GS) override { PipelineStream.GS = GS; }
+    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override { PipelineStream.StreamOutput = StreamOutput; }
+    void HSCb(const D3D12_SHADER_BYTECODE& HS) override { PipelineStream.HS = HS; }
+    void DSCb(const D3D12_SHADER_BYTECODE& DS) override { PipelineStream.DS = DS; }
+    void PSCb(const D3D12_SHADER_BYTECODE& PS) override { PipelineStream.PS = PS; }
+    void CSCb(const D3D12_SHADER_BYTECODE& CS) override { PipelineStream.CS = CS; }
+    void ASCb(const D3D12_SHADER_BYTECODE& AS) override { PipelineStream.AS = AS; }
+    void MSCb(const D3D12_SHADER_BYTECODE& MS) override { PipelineStream.MS = MS; }
+    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override { PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState); }
+    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState2Cb(const D3D12_DEPTH_STENCIL_DESC2& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
+    {
+        PipelineStream.DSVFormat = DSVFormat;
+        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
+        {
+            // Re-enable depth for the default state.
+            static_cast<D3D12_DEPTH_STENCIL_DESC2&>(PipelineStream.DepthStencilState).DepthEnable = true;
+        }
+    }
+    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC2(RasterizerState); }
+    void RasterizerState1Cb(const D3D12_RASTERIZER_DESC1& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC2(RasterizerState); }
+    void RasterizerState2Cb(const D3D12_RASTERIZER_DESC2& RasterizerState) override { PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC2(RasterizerState); }
+    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override { PipelineStream.RTVFormats = RTVFormats; }
+    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override { PipelineStream.SampleDesc = SampleDesc; }
+    void SampleMaskCb(UINT SampleMask) override { PipelineStream.SampleMask = SampleMask; }
+    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override { PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc); }
+    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override { PipelineStream.CachedPSO = CachedPSO; }
+
+private:
+    bool SeenDSS;
+};
+#endif // D3D12_SDK_VERSION >= 610
+
+struct CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER : public ID3DX12PipelineParserCallbacks
+{
+    CD3DX12_PIPELINE_STATE_STREAM1 PipelineStream;
+    CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER() noexcept
+        : SeenDSS(false)
+    {
+        // Adjust defaults to account for absent members.
+        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+        // Depth disabled if no DSV format specified.
+        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;
+    }
+
+    // ID3DX12PipelineParserCallbacks
+    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}
+    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}
+    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}
+    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}
+    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}
+    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}
+    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}
+    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}
+    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}
+    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}
+    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}
+    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}
+    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}
+    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}
+    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override
+    {
+        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);
+        SeenDSS = true;
+    }
+    void DSVFormatCb(DXGI_FORMAT DSVFormat) override
+    {
+        PipelineStream.DSVFormat = DSVFormat;
+        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
+        {
+            // Re-enable depth for the default state.
+            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;
+        }
+    }
+    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}
+    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}
+    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}
+    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}
+    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}
+    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}
+
+private:
+    bool SeenDSS;
+};
+
+inline D3D12_PIPELINE_STATE_SUBOBJECT_TYPE D3DX12GetBaseSubobjectType(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE SubobjectType) noexcept
+{
+    switch (SubobjectType)
+    {
+    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:
+        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2:
+        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1:
+        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER;
+#endif
+    default:
+        return SubobjectType;
+    }
+}
+
+inline HRESULT D3DX12ParsePipelineStream(const D3D12_PIPELINE_STATE_STREAM_DESC& Desc, ID3DX12PipelineParserCallbacks* pCallbacks)
+{
+    if (pCallbacks == nullptr)
+    {
+        return E_INVALIDARG;
+    }
+
+    if (Desc.SizeInBytes == 0 || Desc.pPipelineStateSubobjectStream == nullptr)
+    {
+        pCallbacks->ErrorBadInputParameter(1); // first parameter issue
+        return E_INVALIDARG;
+    }
+
+    bool SubobjectSeen[D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID] = {};
+    for (SIZE_T CurOffset = 0, SizeOfSubobject = 0; CurOffset < Desc.SizeInBytes; CurOffset += SizeOfSubobject)
+    {
+        BYTE* pStream = static_cast<BYTE*>(Desc.pPipelineStateSubobjectStream)+CurOffset;
+        auto SubobjectType = *reinterpret_cast<D3D12_PIPELINE_STATE_SUBOBJECT_TYPE*>(pStream);
+        if (SubobjectType < 0 || SubobjectType >= D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID)
+        {
+            pCallbacks->ErrorUnknownSubobject(SubobjectType);
+            return E_INVALIDARG;
+        }
+        if (SubobjectSeen[D3DX12GetBaseSubobjectType(SubobjectType)])
+        {
+            pCallbacks->ErrorDuplicateSubobject(SubobjectType);
+            return E_INVALIDARG; // disallow subobject duplicates in a stream
+        }
+        SubobjectSeen[SubobjectType] = true;
+        switch (SubobjectType)
+        {
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE:
+            pCallbacks->RootSignatureCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS:
+            pCallbacks->VSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::VS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS:
+            pCallbacks->PSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS:
+            pCallbacks->DSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS:
+            pCallbacks->HSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::HS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS:
+            pCallbacks->GSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::GS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS:
+            pCallbacks->CSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS:
+            pCallbacks->ASCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::AS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS:
+            pCallbacks->MSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::MS)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT:
+            pCallbacks->StreamOutputCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND:
+            pCallbacks->BlendStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::BlendState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK:
+            pCallbacks->SampleMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleMask)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER:
+            pCallbacks->RasterizerStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState);
+            break;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 608)
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1:
+            pCallbacks->RasterizerState1Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM4::RasterizerState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM4::RasterizerState);
+            break;
+#endif
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 610)
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2:
+            pCallbacks->RasterizerState2Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM5::RasterizerState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM5::RasterizerState);
+            break;
+#endif
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL:
+            pCallbacks->DepthStencilStateCb(*reinterpret_cast<CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:
+            pCallbacks->DepthStencilState1Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState);
+            break;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2:
+            pCallbacks->DepthStencilState2Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState);
+            break;
+#endif
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT:
+            pCallbacks->InputLayoutCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::InputLayout)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE:
+            pCallbacks->IBStripCutValueCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY:
+            pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS:
+            pCallbacks->RTVFormatsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT:
+            pCallbacks->DSVFormatCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC:
+            pCallbacks->SampleDescCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK:
+            pCallbacks->NodeMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::NodeMask)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO:
+            pCallbacks->CachedPSOCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS:
+            pCallbacks->FlagsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::Flags)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags);
+            break;
+        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING:
+            pCallbacks->ViewInstancingCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc)*>(pStream));
+            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc);
+            break;
+        default:
+            pCallbacks->ErrorUnknownSubobject(SubobjectType);
+            return E_INVALIDARG;
+        }
+    }
+
+    return S_OK;
+}

+ 124 - 0
thirdparty/directx_headers/include/directx/d3dx12_property_format_table.h

@@ -0,0 +1,124 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+#ifndef __D3D12_PROPERTY_LAYOUT_FORMAT_TABLE_H__
+#define __D3D12_PROPERTY_LAYOUT_FORMAT_TABLE_H__
+#include "d3d12.h"
+#define MAP_ALIGN_REQUIREMENT 16 // Map is required to return 16-byte aligned addresses
+
+struct D3D12_PROPERTY_LAYOUT_FORMAT_TABLE
+{
+public:
+    // ----------------------------------------------------------------------------
+    // Information describing everything about a D3D Resource Format
+    // ----------------------------------------------------------------------------
+    typedef struct FORMAT_DETAIL
+    {
+        DXGI_FORMAT                 DXGIFormat;
+        DXGI_FORMAT                 ParentFormat;
+        const DXGI_FORMAT*          pDefaultFormatCastSet;  // This is dependent on FL/driver version, but is here to save a lot of space
+        UINT8                       BitsPerComponent[4]; // only used for D3DFTL_PARTIAL_TYPE or FULL_TYPE
+        UINT8                       BitsPerUnit;
+        BYTE                        SRGBFormat : 1;
+        UINT                        WidthAlignment : 4;      // number of texels to align to in a mip level.
+        UINT                        HeightAlignment : 4;     // Top level dimensions must be a multiple of these
+        UINT                        DepthAlignment : 1;      // values.
+        D3D_FORMAT_LAYOUT           Layout : 1;
+        D3D_FORMAT_TYPE_LEVEL       TypeLevel : 2;
+        D3D_FORMAT_COMPONENT_NAME   ComponentName0 : 3; // RED    ... only used for D3DFTL_PARTIAL_TYPE or FULL_TYPE
+        D3D_FORMAT_COMPONENT_NAME   ComponentName1 : 3; // GREEN  ... only used for D3DFTL_PARTIAL_TYPE or FULL_TYPE
+        D3D_FORMAT_COMPONENT_NAME   ComponentName2 : 3; // BLUE   ... only used for D3DFTL_PARTIAL_TYPE or FULL_TYPE
+        D3D_FORMAT_COMPONENT_NAME   ComponentName3 : 3; // ALPHA  ... only used for D3DFTL_PARTIAL_TYPE or FULL_TYPE
+        D3D_FORMAT_COMPONENT_INTERPRETATION ComponentInterpretation0 : 3; // only used for D3DFTL_FULL_TYPE
+        D3D_FORMAT_COMPONENT_INTERPRETATION ComponentInterpretation1 : 3; // only used for D3DFTL_FULL_TYPE
+        D3D_FORMAT_COMPONENT_INTERPRETATION ComponentInterpretation2 : 3; // only used for D3DFTL_FULL_TYPE
+        D3D_FORMAT_COMPONENT_INTERPRETATION ComponentInterpretation3 : 3; // only used for D3DFTL_FULL_TYPE
+        bool                        bDX9VertexOrIndexFormat : 1;
+        bool                        bDX9TextureFormat : 1;
+        bool                        bFloatNormFormat : 1;
+        bool                        bPlanar : 1;
+        bool                        bYUV : 1;
+        bool                        bDependantFormatCastSet : 1;  // This indicates that the format cast set is dependent on FL/driver version
+        bool                        bInternal : 1;
+    } FORMAT_DETAIL;
+
+private:
+    static const FORMAT_DETAIL      s_FormatDetail[];
+    static const UINT               s_NumFormats;
+    static const LPCSTR             s_FormatNames[]; // separate from above structure so it can be compiled out of runtime.
+public:
+    static UINT                 GetNumFormats();
+    static const FORMAT_DETAIL* GetFormatTable();
+    static D3D_FEATURE_LEVEL    GetHighestDefinedFeatureLevel();
+
+    static DXGI_FORMAT          GetFormat               (SIZE_T Index);
+    static bool                 FormatExists            (DXGI_FORMAT Format);
+    static bool                 FormatExistsInHeader    (DXGI_FORMAT Format, bool bExternalHeader = true);
+    static UINT                 GetByteAlignment        (DXGI_FORMAT Format);
+    static bool                 IsBlockCompressFormat   (DXGI_FORMAT Format);
+    static LPCSTR               GetName                 (DXGI_FORMAT Format, bool bHideInternalFormats = true);
+    static bool                 IsSRGBFormat            (DXGI_FORMAT Format);
+    static UINT                 GetBitsPerStencil       (DXGI_FORMAT Format);
+    static void                 GetFormatReturnTypes    (DXGI_FORMAT Format, D3D_FORMAT_COMPONENT_INTERPRETATION* pInterpretations); // return array of 4 components
+    static UINT                 GetNumComponentsInFormat(DXGI_FORMAT Format);
+
+    // Converts the sequential component index (range from 0 to GetNumComponentsInFormat()) to
+    // the absolute component index (range 0 to 3).
+    static UINT                                 Sequential2AbsoluteComponentIndex           (DXGI_FORMAT Format, UINT SequentialComponentIndex);
+    static bool                                 CanBeCastEvenFullyTyped                     (DXGI_FORMAT Format, D3D_FEATURE_LEVEL fl);
+    static UINT8                                GetAddressingBitsPerAlignedSize             (DXGI_FORMAT Format);
+    static DXGI_FORMAT                          GetParentFormat                             (DXGI_FORMAT Format);
+    static const DXGI_FORMAT*                   GetFormatCastSet                            (DXGI_FORMAT Format);
+    static D3D_FORMAT_LAYOUT                    GetLayout                                   (DXGI_FORMAT Format);
+    static D3D_FORMAT_TYPE_LEVEL                GetTypeLevel                                (DXGI_FORMAT Format);
+    static UINT                                 GetBitsPerUnit                              (DXGI_FORMAT Format);
+    static UINT                                 GetBitsPerUnitThrow                         (DXGI_FORMAT Format);
+    static UINT                                 GetBitsPerElement                           (DXGI_FORMAT Format); // Legacy function used to support D3D10on9 only. Do not use.
+    static UINT                                 GetWidthAlignment                           (DXGI_FORMAT Format);
+    static UINT                                 GetHeightAlignment                          (DXGI_FORMAT Format);
+    static UINT                                 GetDepthAlignment                           (DXGI_FORMAT Format);
+    static BOOL                                 Planar                                      (DXGI_FORMAT Format);
+    static BOOL                                 NonOpaquePlanar                             (DXGI_FORMAT Format);
+    static BOOL                                 YUV                                         (DXGI_FORMAT Format);
+    static BOOL                                 Opaque                                      (DXGI_FORMAT Format);
+    static bool                                 FamilySupportsStencil                       (DXGI_FORMAT Format);
+    static UINT                                 NonOpaquePlaneCount                         (DXGI_FORMAT Format);
+    static BOOL                                 DX9VertexOrIndexFormat                      (DXGI_FORMAT Format);
+    static BOOL                                 DX9TextureFormat                            (DXGI_FORMAT Format);
+    static BOOL                                 FloatNormTextureFormat                      (DXGI_FORMAT Format);
+    static bool                                 DepthOnlyFormat                             (DXGI_FORMAT format);
+    static UINT8                                GetPlaneCount                               (DXGI_FORMAT Format);
+    static bool                                 MotionEstimatorAllowedInputFormat           (DXGI_FORMAT Format);
+    static bool                                 SupportsSamplerFeedback                     (DXGI_FORMAT Format);
+    static bool                                 DecodeHistogramAllowedForOutputFormatSupport(DXGI_FORMAT Format);
+    static UINT8                                GetPlaneSliceFromViewFormat                 (DXGI_FORMAT ResourceFormat, DXGI_FORMAT ViewFormat);
+    static bool                                 FloatAndNotFloatFormats                     (DXGI_FORMAT FormatA,        DXGI_FORMAT FormatB);
+    static bool                                 SNORMAndUNORMFormats                        (DXGI_FORMAT FormatA,        DXGI_FORMAT FormatB);
+    static bool                                 ValidCastToR32UAV                           (DXGI_FORMAT from,           DXGI_FORMAT to);
+    static bool                                 IsSupportedTextureDisplayableFormat         (DXGI_FORMAT,                bool bMediaFormatOnly);
+    static D3D_FORMAT_COMPONENT_INTERPRETATION  GetFormatComponentInterpretation            (DXGI_FORMAT Format,         UINT AbsoluteComponentIndex);
+    static UINT                                 GetBitsPerComponent                         (DXGI_FORMAT Format,         UINT AbsoluteComponentIndex);
+    static D3D_FORMAT_COMPONENT_NAME            GetComponentName                            (DXGI_FORMAT Format,         UINT AbsoluteComponentIndex);
+    static HRESULT                              CalculateExtraPlanarRows                    (DXGI_FORMAT format,         UINT plane0Height, _Out_ UINT& totalHeight);
+    static HRESULT                              CalculateMinimumRowMajorRowPitch            (DXGI_FORMAT Format,         UINT Width, _Out_ UINT& RowPitch);
+    static HRESULT                              CalculateMinimumRowMajorSlicePitch          (DXGI_FORMAT Format,         UINT ContextBasedRowPitch, UINT Height, _Out_ UINT& SlicePitch);
+    static void                                 GetYCbCrChromaSubsampling                   (DXGI_FORMAT Format,         _Out_ UINT& HorizontalSubsampling, _Out_ UINT& VerticalSubsampling);
+
+    static HRESULT                              CalculateResourceSize               (UINT width, UINT height, UINT depth, DXGI_FORMAT format, UINT mipLevels, UINT subresources, _Out_ SIZE_T& totalByteSize, _Out_writes_opt_(subresources) D3D12_MEMCPY_DEST* pDst = nullptr);
+    static void                                 GetTileShape                        (D3D12_TILE_SHAPE* pTileShape, DXGI_FORMAT Format, D3D12_RESOURCE_DIMENSION Dimension, UINT SampleCount);
+    static void                                 Get4KTileShape                      (D3D12_TILE_SHAPE* pTileShape, DXGI_FORMAT Format, D3D12_RESOURCE_DIMENSION Dimension, UINT SampleCount);
+    static void                                 GetMipDimensions                    (UINT8 mipSlice, _Inout_ UINT64* pWidth, _Inout_opt_ UINT64* pHeight = nullptr, _Inout_opt_ UINT64* pDepth = nullptr);
+    static void                                 GetPlaneSubsampledSizeAndFormatForCopyableLayout(UINT PlaneSlice, DXGI_FORMAT Format, UINT Width, UINT Height, _Out_ DXGI_FORMAT& PlaneFormat, _Out_ UINT& MinPlanePitchWidth, _Out_ UINT& PlaneWidth, _Out_ UINT& PlaneHeight);
+
+    static UINT                                 GetDetailTableIndex         (DXGI_FORMAT  Format);
+    static UINT                                 GetDetailTableIndexNoThrow  (DXGI_FORMAT  Format);
+    static UINT                                 GetDetailTableIndexThrow    (DXGI_FORMAT  Format);
+private:
+    static const FORMAT_DETAIL*                 GetFormatDetail             (DXGI_FORMAT  Format);
+
+};
+
+#endif

+ 102 - 0
thirdparty/directx_headers/include/directx/d3dx12_render_pass.h

@@ -0,0 +1,102 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+inline bool operator==(const D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS& a, const D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS& b) noexcept
+{
+    return ((a.AdditionalWidth == b.AdditionalWidth) && (a.AdditionalHeight == b.AdditionalHeight));
+}
+
+inline bool operator==(const D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS& a, const D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS& b) noexcept
+{
+    return ((a.AdditionalWidth == b.AdditionalWidth) && (a.AdditionalHeight == b.AdditionalHeight));
+}
+
+inline bool operator==(const D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS& a, const D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS& b) noexcept
+{
+    return ((a.AdditionalWidth == b.AdditionalWidth) && (a.AdditionalHeight == b.AdditionalHeight));
+}
+#endif
+
+inline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &b) noexcept
+{
+    return a.ClearValue == b.ClearValue;
+}
+
+inline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &a, const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &b) noexcept
+{
+    if (a.pSrcResource != b.pSrcResource) return false;
+    if (a.pDstResource != b.pDstResource) return false;
+    if (a.SubresourceCount != b.SubresourceCount) return false;
+    if (a.Format != b.Format) return false;
+    if (a.ResolveMode != b.ResolveMode) return false;
+    if (a.PreserveResolveSource != b.PreserveResolveSource) return false;
+    return true;
+}
+
+inline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS &b) noexcept
+{
+    if (a.Type != b.Type) return false;
+    switch (a.Type)
+    {
+    case D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR:
+        if (!(a.Clear == b.Clear)) return false;
+        break;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    case D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER:
+    case D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_SRV:
+    case D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_UAV:
+        if (!(a.PreserveLocal == b.PreserveLocal)) return false;
+        break;
+#endif
+    }
+    return true;
+}
+
+inline bool operator==(const D3D12_RENDER_PASS_ENDING_ACCESS& a, const D3D12_RENDER_PASS_ENDING_ACCESS& b) noexcept
+{
+    if (a.Type != b.Type) return false;
+    switch (a.Type)
+    {
+    case D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE:
+        if (!(a.Resolve == b.Resolve)) return false;
+        break;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    case D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER:
+    case D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_SRV:
+    case D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_UAV:
+        if (!(a.PreserveLocal == b.PreserveLocal)) return false;
+        break;
+#endif
+    }
+
+    return true;
+}
+
+inline bool operator==( const D3D12_RENDER_PASS_RENDER_TARGET_DESC &a, const D3D12_RENDER_PASS_RENDER_TARGET_DESC &b) noexcept
+{
+    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;
+    if (!(a.BeginningAccess == b.BeginningAccess)) return false;
+    if (!(a.EndingAccess == b.EndingAccess)) return false;
+    return true;
+}
+inline bool operator==( const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &a, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &b) noexcept
+{
+    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;
+    if (!(a.DepthBeginningAccess == b.DepthBeginningAccess)) return false;
+    if (!(a.StencilBeginningAccess == b.StencilBeginningAccess)) return false;
+    if (!(a.DepthEndingAccess == b.DepthEndingAccess)) return false;
+    if (!(a.StencilEndingAccess == b.StencilEndingAccess)) return false;
+    return true;
+}

+ 602 - 0
thirdparty/directx_headers/include/directx/d3dx12_resource_helpers.h

@@ -0,0 +1,602 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+#include "d3dx12_core.h"
+#include "d3dx12_property_format_table.h"
+//------------------------------------------------------------------------------------------------
+template <typename T, typename U, typename V>
+inline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept
+{
+    MipSlice = static_cast<T>(Subresource % MipLevels);
+    ArraySlice = static_cast<U>((Subresource / MipLevels) % ArraySize);
+    PlaneSlice = static_cast<V>(Subresource / (MipLevels * ArraySize));
+}
+
+//------------------------------------------------------------------------------------------------
+// Row-by-row memcpy
+inline void MemcpySubresource(
+    _In_ const D3D12_MEMCPY_DEST* pDest,
+    _In_ const D3D12_SUBRESOURCE_DATA* pSrc,
+    SIZE_T RowSizeInBytes,
+    UINT NumRows,
+    UINT NumSlices) noexcept
+{
+    for (UINT z = 0; z < NumSlices; ++z)
+    {
+        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
+        auto pSrcSlice = static_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * LONG_PTR(z);
+        for (UINT y = 0; y < NumRows; ++y)
+        {
+            memcpy(pDestSlice + pDest->RowPitch * y,
+                   pSrcSlice + pSrc->RowPitch * LONG_PTR(y),
+                   RowSizeInBytes);
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+// Row-by-row memcpy
+inline void MemcpySubresource(
+    _In_ const D3D12_MEMCPY_DEST* pDest,
+    _In_ const void* pResourceData,
+    _In_ const D3D12_SUBRESOURCE_INFO* pSrc,
+    SIZE_T RowSizeInBytes,
+    UINT NumRows,
+    UINT NumSlices) noexcept
+{
+    for (UINT z = 0; z < NumSlices; ++z)
+    {
+        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
+        auto pSrcSlice = (static_cast<const BYTE*>(pResourceData) + pSrc->Offset) + pSrc->DepthPitch * ULONG_PTR(z);
+        for (UINT y = 0; y < NumRows; ++y)
+        {
+            memcpy(pDestSlice + pDest->RowPitch * y,
+                pSrcSlice + pSrc->RowPitch * ULONG_PTR(y),
+                RowSizeInBytes);
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+// Returns required size of a buffer to be used for data upload
+inline UINT64 GetRequiredIntermediateSize(
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources) noexcept
+{
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto Desc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc;
+    const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
+#endif
+    UINT64 RequiredSize = 0;
+
+    ID3D12Device* pDevice = nullptr;
+    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
+    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);
+    pDevice->Release();
+
+    return RequiredSize;
+}
+
+//------------------------------------------------------------------------------------------------
+// All arrays must be populated (e.g. by calling GetCopyableFootprints)
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
+    UINT64 RequiredSize,
+    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
+    _In_reads_(NumSubresources) const UINT* pNumRows,
+    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
+{
+    // Minor validation
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto IntermediateDesc = pIntermediate->GetDesc();
+    const auto DestinationDesc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc1, tmpDesc2;
+    const auto& IntermediateDesc = *pIntermediate->GetDesc(&tmpDesc1);
+    const auto& DestinationDesc = *pDestinationResource->GetDesc(&tmpDesc2);
+#endif
+    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
+        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
+        RequiredSize > SIZE_T(-1) ||
+        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
+            (FirstSubresource != 0 || NumSubresources != 1)))
+    {
+        return 0;
+    }
+
+    BYTE* pData;
+    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
+    if (FAILED(hr))
+    {
+        return 0;
+    }
+
+    for (UINT i = 0; i < NumSubresources; ++i)
+    {
+        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
+        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
+        MemcpySubresource(&DestData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
+    }
+    pIntermediate->Unmap(0, nullptr);
+
+    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+    {
+        pCmdList->CopyBufferRegion(
+            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
+    }
+    else
+    {
+        for (UINT i = 0; i < NumSubresources; ++i)
+        {
+            const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
+            const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
+            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
+        }
+    }
+    return RequiredSize;
+}
+
+//------------------------------------------------------------------------------------------------
+// All arrays must be populated (e.g. by calling GetCopyableFootprints)
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
+    UINT64 RequiredSize,
+    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
+    _In_reads_(NumSubresources) const UINT* pNumRows,
+    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
+    _In_ const void* pResourceData,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
+{
+    // Minor validation
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto IntermediateDesc = pIntermediate->GetDesc();
+    const auto DestinationDesc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc1, tmpDesc2;
+    const auto& IntermediateDesc = *pIntermediate->GetDesc(&tmpDesc1);
+    const auto& DestinationDesc = *pDestinationResource->GetDesc(&tmpDesc2);
+#endif
+    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
+        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
+        RequiredSize > SIZE_T(-1) ||
+        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
+            (FirstSubresource != 0 || NumSubresources != 1)))
+    {
+        return 0;
+    }
+
+    BYTE* pData;
+    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
+    if (FAILED(hr))
+    {
+        return 0;
+    }
+
+    for (UINT i = 0; i < NumSubresources; ++i)
+    {
+        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
+        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
+        MemcpySubresource(&DestData, pResourceData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
+    }
+    pIntermediate->Unmap(0, nullptr);
+
+    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+    {
+        pCmdList->CopyBufferRegion(
+            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
+    }
+    else
+    {
+        for (UINT i = 0; i < NumSubresources; ++i)
+        {
+            const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
+            const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
+            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
+        }
+    }
+    return RequiredSize;
+}
+
+//------------------------------------------------------------------------------------------------
+// Heap-allocating UpdateSubresources implementation
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    UINT64 IntermediateOffset,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
+{
+    UINT64 RequiredSize = 0;
+    const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
+    if (MemToAlloc > SIZE_MAX)
+    {
+       return 0;
+    }
+    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
+    if (pMem == nullptr)
+    {
+       return 0;
+    }
+    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
+    auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
+    auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
+
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto Desc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc;
+    const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
+#endif
+    ID3D12Device* pDevice = nullptr;
+    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
+    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
+    pDevice->Release();
+
+    const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);
+    HeapFree(GetProcessHeap(), 0, pMem);
+    return Result;
+}
+
+//------------------------------------------------------------------------------------------------
+// Heap-allocating UpdateSubresources implementation
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    UINT64 IntermediateOffset,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
+    _In_ const void* pResourceData,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
+{
+    UINT64 RequiredSize = 0;
+    const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
+    if (MemToAlloc > SIZE_MAX)
+    {
+        return 0;
+    }
+    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
+    if (pMem == nullptr)
+    {
+        return 0;
+    }
+    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
+    auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
+    auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
+
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto Desc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc;
+    const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
+#endif
+    ID3D12Device* pDevice = nullptr;
+    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
+    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
+    pDevice->Release();
+
+    const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pResourceData, pSrcData);
+    HeapFree(GetProcessHeap(), 0, pMem);
+    return Result;
+}
+
+//------------------------------------------------------------------------------------------------
+// Stack-allocating UpdateSubresources implementation
+template <UINT MaxSubresources>
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    UINT64 IntermediateOffset,
+    _In_range_(0,MaxSubresources) UINT FirstSubresource,
+    _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
+{
+    UINT64 RequiredSize = 0;
+    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
+    UINT NumRows[MaxSubresources];
+    UINT64 RowSizesInBytes[MaxSubresources];
+
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto Desc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc;
+    const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
+#endif
+    ID3D12Device* pDevice = nullptr;
+    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
+    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
+    pDevice->Release();
+
+    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pSrcData);
+}
+
+//------------------------------------------------------------------------------------------------
+// Stack-allocating UpdateSubresources implementation
+template <UINT MaxSubresources>
+inline UINT64 UpdateSubresources(
+    _In_ ID3D12GraphicsCommandList* pCmdList,
+    _In_ ID3D12Resource* pDestinationResource,
+    _In_ ID3D12Resource* pIntermediate,
+    UINT64 IntermediateOffset,
+    _In_range_(0,MaxSubresources) UINT FirstSubresource,
+    _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
+    _In_ const void* pResourceData,
+    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
+{
+    UINT64 RequiredSize = 0;
+    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
+    UINT NumRows[MaxSubresources];
+    UINT64 RowSizesInBytes[MaxSubresources];
+
+#if defined(_MSC_VER) || !defined(_WIN32)
+    const auto Desc = pDestinationResource->GetDesc();
+#else
+    D3D12_RESOURCE_DESC tmpDesc;
+    const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
+#endif
+    ID3D12Device* pDevice = nullptr;
+    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
+    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
+    pDevice->Release();
+
+    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pResourceData, pSrcData);
+}
+
+//------------------------------------------------------------------------------------------------
+constexpr bool D3D12IsLayoutOpaque( D3D12_TEXTURE_LAYOUT Layout ) noexcept
+{ return Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN || Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; }
+
+//------------------------------------------------------------------------------------------------
+template< typename T >
+inline T D3DX12Align(T uValue, T uAlign)
+{
+    // Assert power of 2 alignment
+    D3DX12_ASSERT(0 == (uAlign & (uAlign - 1)));
+    T uMask = uAlign - 1;
+    T uResult = (uValue + uMask) & ~uMask;
+    D3DX12_ASSERT(uResult >= uValue);
+    D3DX12_ASSERT(0 == (uResult % uAlign));
+    return uResult;
+}
+
+//------------------------------------------------------------------------------------------------
+template< typename T >
+inline T D3DX12AlignAtLeast(T uValue, T uAlign)
+{
+    T aligned = D3DX12Align(uValue, uAlign);
+    return aligned > uAlign ? aligned : uAlign;
+}
+
+inline const CD3DX12_RESOURCE_DESC1* D3DX12ConditionallyExpandAPIDesc(
+    D3D12_RESOURCE_DESC1& LclDesc,
+    const D3D12_RESOURCE_DESC1* pDesc)
+{
+    return D3DX12ConditionallyExpandAPIDesc(static_cast<CD3DX12_RESOURCE_DESC1&>(LclDesc), static_cast<const CD3DX12_RESOURCE_DESC1*>(pDesc));
+}
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
+//------------------------------------------------------------------------------------------------
+// The difference between D3DX12GetCopyableFootprints and ID3D12Device::GetCopyableFootprints
+// is that this one loses a lot of error checking by assuming the arguments are correct
+inline bool D3DX12GetCopyableFootprints(
+    _In_  const D3D12_RESOURCE_DESC1& ResourceDesc,
+    _In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+    _In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources,
+    UINT64 BaseOffset,
+    _Out_writes_opt_(NumSubresources) D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
+    _Out_writes_opt_(NumSubresources) UINT* pNumRows,
+    _Out_writes_opt_(NumSubresources) UINT64* pRowSizeInBytes,
+    _Out_opt_ UINT64* pTotalBytes)
+{
+    constexpr UINT64 uint64_max = ~0ull;
+    UINT64 TotalBytes = uint64_max;
+    UINT uSubRes = 0;
+
+    bool bResourceOverflow = false;
+    TotalBytes = 0;
+
+    const DXGI_FORMAT Format = ResourceDesc.Format;
+
+    CD3DX12_RESOURCE_DESC1 LresourceDesc;
+    const CD3DX12_RESOURCE_DESC1& resourceDesc = *D3DX12ConditionallyExpandAPIDesc(LresourceDesc, &ResourceDesc);
+
+    // Check if its a valid format
+    D3DX12_ASSERT(D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::FormatExists(Format));
+
+    const UINT WidthAlignment = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetWidthAlignment( Format );
+    const UINT HeightAlignment = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetHeightAlignment( Format );
+    const UINT16 DepthAlignment = UINT16( D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetDepthAlignment( Format ) );
+
+    for (; uSubRes < NumSubresources; ++uSubRes)
+    {
+        bool bOverflow = false;
+        UINT Subresource = FirstSubresource + uSubRes;
+
+        D3DX12_ASSERT(resourceDesc.MipLevels != 0);
+        UINT subresourceCount = resourceDesc.MipLevels * resourceDesc.ArraySize() * D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetPlaneCount(resourceDesc.Format);
+
+        if (Subresource > subresourceCount)
+        {
+            break;
+        }
+
+        TotalBytes = D3DX12Align< UINT64 >( TotalBytes, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT );
+
+        UINT MipLevel, ArraySlice, PlaneSlice;
+        D3D12DecomposeSubresource(Subresource, resourceDesc.MipLevels, resourceDesc.ArraySize(), /*_Out_*/MipLevel, /*_Out_*/ArraySlice, /*_Out_*/PlaneSlice);
+
+        const UINT64 Width = D3DX12AlignAtLeast<UINT64>(resourceDesc.Width >> MipLevel, WidthAlignment);
+        const UINT Height =  D3DX12AlignAtLeast(resourceDesc.Height >> MipLevel, HeightAlignment);
+        const UINT16 Depth = D3DX12AlignAtLeast<UINT16>(resourceDesc.Depth() >> MipLevel, DepthAlignment);
+
+        // Adjust for the current PlaneSlice.  Most formats have only one plane.
+        DXGI_FORMAT PlaneFormat;
+        UINT32 MinPlanePitchWidth, PlaneWidth, PlaneHeight;
+        D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetPlaneSubsampledSizeAndFormatForCopyableLayout(PlaneSlice, Format, (UINT)Width, Height, /*_Out_*/ PlaneFormat, /*_Out_*/ MinPlanePitchWidth, /* _Out_ */ PlaneWidth, /*_Out_*/ PlaneHeight);
+
+        D3D12_SUBRESOURCE_FOOTPRINT LocalPlacement;
+        auto& Placement = pLayouts ? pLayouts[uSubRes].Footprint : LocalPlacement;
+        Placement.Format = PlaneFormat;
+        Placement.Width = PlaneWidth;
+        Placement.Height = PlaneHeight;
+        Placement.Depth = Depth;
+
+        // Calculate row pitch
+        UINT MinPlaneRowPitch = 0;
+        D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::CalculateMinimumRowMajorRowPitch(PlaneFormat, MinPlanePitchWidth, MinPlaneRowPitch);
+
+        // Formats with more than one plane choose a larger pitch alignment to ensure that each plane begins on the row
+        // immediately following the previous plane while still adhering to subresource alignment restrictions.
+        static_assert(   D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT >= D3D12_TEXTURE_DATA_PITCH_ALIGNMENT
+                        && ((D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) == 0),
+                        "D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT  must be >= and evenly divisible by D3D12_TEXTURE_DATA_PITCH_ALIGNMENT." );
+
+        Placement.RowPitch = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::Planar(Format)
+            ? D3DX12Align< UINT >( MinPlaneRowPitch, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT )
+            : D3DX12Align< UINT >( MinPlaneRowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT );
+
+        if (pRowSizeInBytes)
+        {
+            UINT PlaneRowSize = 0;
+            D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::CalculateMinimumRowMajorRowPitch(PlaneFormat, PlaneWidth, PlaneRowSize);
+
+            pRowSizeInBytes[uSubRes] = PlaneRowSize;
+        }
+
+        // Number of rows (accounting for block compression and additional planes)
+        UINT NumRows = 0;
+        if (D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::Planar(Format))
+        {
+            NumRows = PlaneHeight;
+        }
+        else
+        {
+            D3DX12_ASSERT(Height % HeightAlignment == 0);
+            NumRows = Height / HeightAlignment;
+        }
+
+        if (pNumRows)
+        {
+            pNumRows[uSubRes] = NumRows;
+        }
+
+            // Offsetting
+            if (pLayouts)
+            {
+                pLayouts[uSubRes].Offset = (bOverflow ? uint64_max : TotalBytes + BaseOffset);
+            }
+
+        const UINT16 NumSlices = Depth;
+        const UINT64 SubresourceSize = (NumRows * NumSlices - 1) * Placement.RowPitch + MinPlaneRowPitch;
+
+        // uint64 addition with overflow checking
+        TotalBytes = TotalBytes + SubresourceSize;
+        if(TotalBytes < SubresourceSize)
+        {
+            TotalBytes = uint64_max;
+        }
+        bResourceOverflow  = bResourceOverflow  || bOverflow;
+    }
+
+    // Overflow error
+    if (bResourceOverflow)
+    {
+        TotalBytes = uint64_max;
+    }
+
+
+    if (pLayouts)
+    {
+        memset( pLayouts + uSubRes, -1, sizeof( *pLayouts ) * (NumSubresources - uSubRes) );
+    }
+    if (pNumRows)
+    {
+        memset(pNumRows + uSubRes, -1, sizeof(*pNumRows) * (NumSubresources - uSubRes));
+    }
+    if (pRowSizeInBytes)
+    {
+        memset(pRowSizeInBytes + uSubRes, -1, sizeof(*pRowSizeInBytes) * (NumSubresources - uSubRes));
+    }
+    if (pTotalBytes)
+    {
+        *pTotalBytes = TotalBytes;
+    }
+    if(TotalBytes == uint64_max)
+    {
+        return false;
+    }
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------
+inline D3D12_RESOURCE_DESC1 D3DX12ResourceDesc0ToDesc1(D3D12_RESOURCE_DESC const& desc0)
+{
+    D3D12_RESOURCE_DESC1       desc1;
+    desc1.Dimension          = desc0.Dimension;
+    desc1.Alignment          = desc0.Alignment;
+    desc1.Width              = desc0.Width;
+    desc1.Height             = desc0.Height;
+    desc1.DepthOrArraySize   = desc0.DepthOrArraySize;
+    desc1.MipLevels          = desc0.MipLevels;
+    desc1.Format             = desc0.Format;
+    desc1.SampleDesc.Count   = desc0.SampleDesc.Count;
+    desc1.SampleDesc.Quality = desc0.SampleDesc.Quality;
+    desc1.Layout             = desc0.Layout;
+    desc1.Flags              = desc0.Flags;
+    desc1.SamplerFeedbackMipRegion.Width = 0;
+    desc1.SamplerFeedbackMipRegion.Height = 0;
+    desc1.SamplerFeedbackMipRegion.Depth = 0;
+    return desc1;
+}
+
+//------------------------------------------------------------------------------------------------
+inline bool D3DX12GetCopyableFootprints(
+	_In_  const D3D12_RESOURCE_DESC& pResourceDesc,
+	_In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
+	_In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources,
+	UINT64 BaseOffset,
+	_Out_writes_opt_(NumSubresources) D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
+	_Out_writes_opt_(NumSubresources) UINT* pNumRows,
+	_Out_writes_opt_(NumSubresources) UINT64* pRowSizeInBytes,
+	_Out_opt_ UINT64* pTotalBytes)
+{
+    // From D3D12_RESOURCE_DESC to D3D12_RESOURCE_DESC1
+    D3D12_RESOURCE_DESC1 desc = D3DX12ResourceDesc0ToDesc1(pResourceDesc);
+	return D3DX12GetCopyableFootprints(
+		*static_cast<CD3DX12_RESOURCE_DESC1*>(&desc),// From D3D12_RESOURCE_DESC1 to CD3DX12_RESOURCE_DESC1
+		FirstSubresource,
+		NumSubresources,
+		BaseOffset,
+		pLayouts,
+		pNumRows,
+		pRowSizeInBytes,
+		pTotalBytes);
+}
+
+#endif // D3D12_SDK_VERSION >= 606

+ 1204 - 0
thirdparty/directx_headers/include/directx/d3dx12_root_signature.h

@@ -0,0 +1,1204 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+#include "d3dx12_default.h"
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_DESCRIPTOR_RANGE : public D3D12_DESCRIPTOR_RANGE
+{
+    CD3DX12_DESCRIPTOR_RANGE() = default;
+    explicit CD3DX12_DESCRIPTOR_RANGE(const D3D12_DESCRIPTOR_RANGE &o) noexcept :
+        D3D12_DESCRIPTOR_RANGE(o)
+    {}
+    CD3DX12_DESCRIPTOR_RANGE(
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);
+    }
+
+    inline void Init(
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_DESCRIPTOR_RANGE &range,
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        range.RangeType = rangeType;
+        range.NumDescriptors = numDescriptors;
+        range.BaseShaderRegister = baseShaderRegister;
+        range.RegisterSpace = registerSpace;
+        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_DESCRIPTOR_TABLE : public D3D12_ROOT_DESCRIPTOR_TABLE
+{
+    CD3DX12_ROOT_DESCRIPTOR_TABLE() = default;
+    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE(const D3D12_ROOT_DESCRIPTOR_TABLE &o) noexcept :
+        D3D12_ROOT_DESCRIPTOR_TABLE(o)
+    {}
+    CD3DX12_ROOT_DESCRIPTOR_TABLE(
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
+    {
+        Init(numDescriptorRanges, _pDescriptorRanges);
+    }
+
+    inline void Init(
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
+    {
+        Init(*this, numDescriptorRanges, _pDescriptorRanges);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE &rootDescriptorTable,
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept
+    {
+        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;
+        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_CONSTANTS : public D3D12_ROOT_CONSTANTS
+{
+    CD3DX12_ROOT_CONSTANTS() = default;
+    explicit CD3DX12_ROOT_CONSTANTS(const D3D12_ROOT_CONSTANTS &o) noexcept :
+        D3D12_ROOT_CONSTANTS(o)
+    {}
+    CD3DX12_ROOT_CONSTANTS(
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0) noexcept
+    {
+        Init(num32BitValues, shaderRegister, registerSpace);
+    }
+
+    inline void Init(
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0) noexcept
+    {
+        Init(*this, num32BitValues, shaderRegister, registerSpace);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_ROOT_CONSTANTS &rootConstants,
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0) noexcept
+    {
+        rootConstants.Num32BitValues = num32BitValues;
+        rootConstants.ShaderRegister = shaderRegister;
+        rootConstants.RegisterSpace = registerSpace;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_DESCRIPTOR : public D3D12_ROOT_DESCRIPTOR
+{
+    CD3DX12_ROOT_DESCRIPTOR() = default;
+    explicit CD3DX12_ROOT_DESCRIPTOR(const D3D12_ROOT_DESCRIPTOR &o) noexcept :
+        D3D12_ROOT_DESCRIPTOR(o)
+    {}
+    CD3DX12_ROOT_DESCRIPTOR(
+        UINT shaderRegister,
+        UINT registerSpace = 0) noexcept
+    {
+        Init(shaderRegister, registerSpace);
+    }
+
+    inline void Init(
+        UINT shaderRegister,
+        UINT registerSpace = 0) noexcept
+    {
+        Init(*this, shaderRegister, registerSpace);
+    }
+
+    static inline void Init(_Out_ D3D12_ROOT_DESCRIPTOR &table, UINT shaderRegister, UINT registerSpace = 0) noexcept
+    {
+        table.ShaderRegister = shaderRegister;
+        table.RegisterSpace = registerSpace;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_PARAMETER : public D3D12_ROOT_PARAMETER
+{
+    CD3DX12_ROOT_PARAMETER() = default;
+    explicit CD3DX12_ROOT_PARAMETER(const D3D12_ROOT_PARAMETER &o) noexcept :
+        D3D12_ROOT_PARAMETER(o)
+    {}
+
+    static inline void InitAsDescriptorTable(
+        _Out_ D3D12_ROOT_PARAMETER &rootParam,
+        UINT numDescriptorRanges,
+        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR_TABLE::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);
+    }
+
+    static inline void InitAsConstants(
+        _Out_ D3D12_ROOT_PARAMETER &rootParam,
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);
+    }
+
+    static inline void InitAsConstantBufferView(
+        _Out_ D3D12_ROOT_PARAMETER &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
+    }
+
+    static inline void InitAsShaderResourceView(
+        _Out_ D3D12_ROOT_PARAMETER &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
+    }
+
+    static inline void InitAsUnorderedAccessView(
+        _Out_ D3D12_ROOT_PARAMETER &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);
+    }
+
+    inline void InitAsDescriptorTable(
+        UINT numDescriptorRanges,
+        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);
+    }
+
+    inline void InitAsConstants(
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);
+    }
+
+    inline void InitAsConstantBufferView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsConstantBufferView(*this, shaderRegister, registerSpace, visibility);
+    }
+
+    inline void InitAsShaderResourceView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsShaderResourceView(*this, shaderRegister, registerSpace, visibility);
+    }
+
+    inline void InitAsUnorderedAccessView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, visibility);
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_STATIC_SAMPLER_DESC : public D3D12_STATIC_SAMPLER_DESC
+{
+    CD3DX12_STATIC_SAMPLER_DESC() = default;
+    explicit CD3DX12_STATIC_SAMPLER_DESC(const D3D12_STATIC_SAMPLER_DESC &o) noexcept :
+        D3D12_STATIC_SAMPLER_DESC(o)
+    {}
+    CD3DX12_STATIC_SAMPLER_DESC(
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0) noexcept
+    {
+        Init(
+            shaderRegister,
+            filter,
+            addressU,
+            addressV,
+            addressW,
+            mipLODBias,
+            maxAnisotropy,
+            comparisonFunc,
+            borderColor,
+            minLOD,
+            maxLOD,
+            shaderVisibility,
+            registerSpace);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_STATIC_SAMPLER_DESC &samplerDesc,
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0) noexcept
+    {
+        samplerDesc.ShaderRegister = shaderRegister;
+        samplerDesc.Filter = filter;
+        samplerDesc.AddressU = addressU;
+        samplerDesc.AddressV = addressV;
+        samplerDesc.AddressW = addressW;
+        samplerDesc.MipLODBias = mipLODBias;
+        samplerDesc.MaxAnisotropy = maxAnisotropy;
+        samplerDesc.ComparisonFunc = comparisonFunc;
+        samplerDesc.BorderColor = borderColor;
+        samplerDesc.MinLOD = minLOD;
+        samplerDesc.MaxLOD = maxLOD;
+        samplerDesc.ShaderVisibility = shaderVisibility;
+        samplerDesc.RegisterSpace = registerSpace;
+    }
+    inline void Init(
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0) noexcept
+    {
+        Init(
+            *this,
+            shaderRegister,
+            filter,
+            addressU,
+            addressV,
+            addressW,
+            mipLODBias,
+            maxAnisotropy,
+            comparisonFunc,
+            borderColor,
+            minLOD,
+            maxLOD,
+            shaderVisibility,
+            registerSpace);
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+struct CD3DX12_STATIC_SAMPLER_DESC1 : public D3D12_STATIC_SAMPLER_DESC1
+{
+    CD3DX12_STATIC_SAMPLER_DESC1() = default;
+    explicit CD3DX12_STATIC_SAMPLER_DESC1(const D3D12_STATIC_SAMPLER_DESC &o) noexcept
+    {
+        memcpy(this, &o, sizeof(D3D12_STATIC_SAMPLER_DESC));
+        Flags = D3D12_SAMPLER_FLAGS::D3D12_SAMPLER_FLAG_NONE;
+    }
+    explicit CD3DX12_STATIC_SAMPLER_DESC1(const D3D12_STATIC_SAMPLER_DESC1 & o) noexcept :
+        D3D12_STATIC_SAMPLER_DESC1(o)
+    {}
+    CD3DX12_STATIC_SAMPLER_DESC1(
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0,
+         D3D12_SAMPLER_FLAGS flags = D3D12_SAMPLER_FLAGS::D3D12_SAMPLER_FLAG_NONE) noexcept
+    {
+        Init(
+            shaderRegister,
+            filter,
+            addressU,
+            addressV,
+            addressW,
+            mipLODBias,
+            maxAnisotropy,
+            comparisonFunc,
+            borderColor,
+            minLOD,
+            maxLOD,
+            shaderVisibility,
+            registerSpace,
+            flags);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_STATIC_SAMPLER_DESC1 &samplerDesc,
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0,
+        D3D12_SAMPLER_FLAGS flags = D3D12_SAMPLER_FLAGS::D3D12_SAMPLER_FLAG_NONE) noexcept
+    {
+        samplerDesc.ShaderRegister = shaderRegister;
+        samplerDesc.Filter = filter;
+        samplerDesc.AddressU = addressU;
+        samplerDesc.AddressV = addressV;
+        samplerDesc.AddressW = addressW;
+        samplerDesc.MipLODBias = mipLODBias;
+        samplerDesc.MaxAnisotropy = maxAnisotropy;
+        samplerDesc.ComparisonFunc = comparisonFunc;
+        samplerDesc.BorderColor = borderColor;
+        samplerDesc.MinLOD = minLOD;
+        samplerDesc.MaxLOD = maxLOD;
+        samplerDesc.ShaderVisibility = shaderVisibility;
+        samplerDesc.RegisterSpace = registerSpace;
+        samplerDesc.Flags = flags;
+    }
+    inline void Init(
+         UINT shaderRegister,
+         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,
+         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+         FLOAT mipLODBias = 0,
+         UINT maxAnisotropy = 16,
+         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,
+         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
+         FLOAT minLOD = 0.f,
+         FLOAT maxLOD = D3D12_FLOAT32_MAX,
+         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
+         UINT registerSpace = 0,
+         D3D12_SAMPLER_FLAGS flags = D3D12_SAMPLER_FLAGS::D3D12_SAMPLER_FLAG_NONE) noexcept
+    {
+        Init(
+            *this,
+            shaderRegister,
+            filter,
+            addressU,
+            addressV,
+            addressW,
+            mipLODBias,
+            maxAnisotropy,
+            comparisonFunc,
+            borderColor,
+            minLOD,
+            maxLOD,
+            shaderVisibility,
+            registerSpace,
+            flags);
+    }
+};
+#endif // D3D12_SDK_VERSION >= 609
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_SIGNATURE_DESC : public D3D12_ROOT_SIGNATURE_DESC
+{
+    CD3DX12_ROOT_SIGNATURE_DESC() = default;
+    explicit CD3DX12_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept :
+        D3D12_ROOT_SIGNATURE_DESC(o)
+    {}
+    CD3DX12_ROOT_SIGNATURE_DESC(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+    CD3DX12_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept
+    {
+        Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
+    }
+
+    inline void Init(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_ROOT_SIGNATURE_DESC &desc,
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        desc.NumParameters = numParameters;
+        desc.pParameters = _pParameters;
+        desc.NumStaticSamplers = numStaticSamplers;
+        desc.pStaticSamplers = _pStaticSamplers;
+        desc.Flags = flags;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_DESCRIPTOR_RANGE1 : public D3D12_DESCRIPTOR_RANGE1
+{
+    CD3DX12_DESCRIPTOR_RANGE1() = default;
+    explicit CD3DX12_DESCRIPTOR_RANGE1(const D3D12_DESCRIPTOR_RANGE1 &o) noexcept :
+        D3D12_DESCRIPTOR_RANGE1(o)
+    {}
+    CD3DX12_DESCRIPTOR_RANGE1(
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);
+    }
+
+    inline void Init(
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_DESCRIPTOR_RANGE1 &range,
+        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
+        UINT numDescriptors,
+        UINT baseShaderRegister,
+        UINT registerSpace = 0,
+        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
+        UINT offsetInDescriptorsFromTableStart =
+        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept
+    {
+        range.RangeType = rangeType;
+        range.NumDescriptors = numDescriptors;
+        range.BaseShaderRegister = baseShaderRegister;
+        range.RegisterSpace = registerSpace;
+        range.Flags = flags;
+        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_DESCRIPTOR_TABLE1 : public D3D12_ROOT_DESCRIPTOR_TABLE1
+{
+    CD3DX12_ROOT_DESCRIPTOR_TABLE1() = default;
+    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE1(const D3D12_ROOT_DESCRIPTOR_TABLE1 &o) noexcept :
+        D3D12_ROOT_DESCRIPTOR_TABLE1(o)
+    {}
+    CD3DX12_ROOT_DESCRIPTOR_TABLE1(
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
+    {
+        Init(numDescriptorRanges, _pDescriptorRanges);
+    }
+
+    inline void Init(
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
+    {
+        Init(*this, numDescriptorRanges, _pDescriptorRanges);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE1 &rootDescriptorTable,
+        UINT numDescriptorRanges,
+        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept
+    {
+        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;
+        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_DESCRIPTOR1 : public D3D12_ROOT_DESCRIPTOR1
+{
+    CD3DX12_ROOT_DESCRIPTOR1() = default;
+    explicit CD3DX12_ROOT_DESCRIPTOR1(const D3D12_ROOT_DESCRIPTOR1 &o) noexcept :
+        D3D12_ROOT_DESCRIPTOR1(o)
+    {}
+    CD3DX12_ROOT_DESCRIPTOR1(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
+    {
+        Init(shaderRegister, registerSpace, flags);
+    }
+
+    inline void Init(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
+    {
+        Init(*this, shaderRegister, registerSpace, flags);
+    }
+
+    static inline void Init(
+        _Out_ D3D12_ROOT_DESCRIPTOR1 &table,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept
+    {
+        table.ShaderRegister = shaderRegister;
+        table.RegisterSpace = registerSpace;
+        table.Flags = flags;
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_ROOT_PARAMETER1 : public D3D12_ROOT_PARAMETER1
+{
+    CD3DX12_ROOT_PARAMETER1() = default;
+    explicit CD3DX12_ROOT_PARAMETER1(const D3D12_ROOT_PARAMETER1 &o) noexcept :
+        D3D12_ROOT_PARAMETER1(o)
+    {}
+
+    static inline void InitAsDescriptorTable(
+        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
+        UINT numDescriptorRanges,
+        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR_TABLE1::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);
+    }
+
+    static inline void InitAsConstants(
+        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);
+    }
+
+    static inline void InitAsConstantBufferView(
+        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
+    }
+
+    static inline void InitAsShaderResourceView(
+        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
+    }
+
+    static inline void InitAsUnorderedAccessView(
+        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
+        rootParam.ShaderVisibility = visibility;
+        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);
+    }
+
+    inline void InitAsDescriptorTable(
+        UINT numDescriptorRanges,
+        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);
+    }
+
+    inline void InitAsConstants(
+        UINT num32BitValues,
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);
+    }
+
+    inline void InitAsConstantBufferView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsConstantBufferView(*this, shaderRegister, registerSpace, flags, visibility);
+    }
+
+    inline void InitAsShaderResourceView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsShaderResourceView(*this, shaderRegister, registerSpace, flags, visibility);
+    }
+
+    inline void InitAsUnorderedAccessView(
+        UINT shaderRegister,
+        UINT registerSpace = 0,
+        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
+        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept
+    {
+        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, flags, visibility);
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC : public D3D12_VERSIONED_ROOT_SIGNATURE_DESC
+{
+    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC() = default;
+    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC &o) noexcept :
+        D3D12_VERSIONED_ROOT_SIGNATURE_DESC(o)
+    {}
+    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept
+    {
+        Version = D3D_ROOT_SIGNATURE_VERSION_1_0;
+        Desc_1_0 = o;
+    }
+    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC1 &o) noexcept
+    {
+        Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
+        Desc_1_1 = o;
+    }
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC2& o) noexcept
+    {
+        Version = D3D_ROOT_SIGNATURE_VERSION_1_2;
+        Desc_1_2 = o;
+    }
+#endif
+    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init_1_0(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init_1_1(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept
+    {
+        Init_1_1(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
+    }
+
+    inline void Init_1_0(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init_1_0(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+
+    static inline void Init_1_0(
+        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0;
+        desc.Desc_1_0.NumParameters = numParameters;
+        desc.Desc_1_0.pParameters = _pParameters;
+        desc.Desc_1_0.NumStaticSamplers = numStaticSamplers;
+        desc.Desc_1_0.pStaticSamplers = _pStaticSamplers;
+        desc.Desc_1_0.Flags = flags;
+    }
+
+    inline void Init_1_1(
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        Init_1_1(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);
+    }
+
+    static inline void Init_1_1(
+        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
+        desc.Desc_1_1.NumParameters = numParameters;
+        desc.Desc_1_1.pParameters = _pParameters;
+        desc.Desc_1_1.NumStaticSamplers = numStaticSamplers;
+        desc.Desc_1_1.pStaticSamplers = _pStaticSamplers;
+        desc.Desc_1_1.Flags = flags;
+    }
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+    static inline void Init_1_2(
+        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC& desc,
+        UINT numParameters,
+        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,
+        UINT numStaticSamplers = 0,
+        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC1* _pStaticSamplers = nullptr,
+        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept
+    {
+        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_2;
+        desc.Desc_1_2.NumParameters = numParameters;
+        desc.Desc_1_2.pParameters = _pParameters;
+        desc.Desc_1_2.NumStaticSamplers = numStaticSamplers;
+        desc.Desc_1_2.pStaticSamplers = _pStaticSamplers;
+        desc.Desc_1_2.Flags = flags;
+    }
+#endif
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_CPU_DESCRIPTOR_HANDLE : public D3D12_CPU_DESCRIPTOR_HANDLE
+{
+    CD3DX12_CPU_DESCRIPTOR_HANDLE() = default;
+    explicit CD3DX12_CPU_DESCRIPTOR_HANDLE(const D3D12_CPU_DESCRIPTOR_HANDLE &o) noexcept :
+        D3D12_CPU_DESCRIPTOR_HANDLE(o)
+    {}
+    CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }
+    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept
+    {
+        InitOffsetted(other, offsetScaledByIncrementSize);
+    }
+    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);
+    }
+    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        ptr = SIZE_T(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
+        return *this;
+    }
+    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept
+    {
+        ptr = SIZE_T(INT64(ptr) + INT64(offsetScaledByIncrementSize));
+        return *this;
+    }
+    bool operator==(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept
+    {
+        return (ptr == other.ptr);
+    }
+    bool operator!=(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept
+    {
+        return (ptr != other.ptr);
+    }
+    CD3DX12_CPU_DESCRIPTOR_HANDLE &operator=(const D3D12_CPU_DESCRIPTOR_HANDLE &other) noexcept
+    {
+        ptr = other.ptr;
+        return *this;
+    }
+
+    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
+    {
+        InitOffsetted(*this, base, offsetScaledByIncrementSize);
+    }
+
+    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);
+    }
+
+    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
+    {
+        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));
+    }
+
+    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+struct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE
+{
+    CD3DX12_GPU_DESCRIPTOR_HANDLE() = default;
+    explicit CD3DX12_GPU_DESCRIPTOR_HANDLE(const D3D12_GPU_DESCRIPTOR_HANDLE &o) noexcept :
+        D3D12_GPU_DESCRIPTOR_HANDLE(o)
+    {}
+    CD3DX12_GPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }
+    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept
+    {
+        InitOffsetted(other, offsetScaledByIncrementSize);
+    }
+    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);
+    }
+    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        ptr = UINT64(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
+        return *this;
+    }
+    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept
+    {
+        ptr = UINT64(INT64(ptr) + INT64(offsetScaledByIncrementSize));
+        return *this;
+    }
+    inline bool operator==(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept
+    {
+        return (ptr == other.ptr);
+    }
+    inline bool operator!=(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept
+    {
+        return (ptr != other.ptr);
+    }
+    CD3DX12_GPU_DESCRIPTOR_HANDLE &operator=(const D3D12_GPU_DESCRIPTOR_HANDLE &other) noexcept
+    {
+        ptr = other.ptr;
+        return *this;
+    }
+
+    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
+    {
+        InitOffsetted(*this, base, offsetScaledByIncrementSize);
+    }
+
+    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);
+    }
+
+    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept
+    {
+        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));
+    }
+
+    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept
+    {
+        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+// D3D12 exports a new method for serializing root signatures in the Windows 10 Anniversary Update.
+// To help enable root signature 1.1 features when they are available and not require maintaining
+// two code paths for building root signatures, this helper method reconstructs a 1.0 signature when
+// 1.1 is not supported.
+inline HRESULT D3DX12SerializeVersionedRootSignature(
+    _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc,
+    D3D_ROOT_SIGNATURE_VERSION MaxVersion,
+    _Outptr_ ID3DBlob** ppBlob,
+    _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorBlob) noexcept
+{
+    if (ppErrorBlob != nullptr)
+    {
+        *ppErrorBlob = nullptr;
+    }
+
+    switch (MaxVersion)
+    {
+        case D3D_ROOT_SIGNATURE_VERSION_1_0:
+            switch (pRootSignatureDesc->Version)
+            {
+                case D3D_ROOT_SIGNATURE_VERSION_1_0:
+                    return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);
+
+                case D3D_ROOT_SIGNATURE_VERSION_1_1:
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+                case D3D_ROOT_SIGNATURE_VERSION_1_2:
+#endif
+                {
+                    HRESULT hr = S_OK;
+                    const D3D12_ROOT_SIGNATURE_DESC1& desc_1_1 = pRootSignatureDesc->Desc_1_1;
+
+                    const SIZE_T ParametersSize = sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters;
+                    void* pParameters = (ParametersSize > 0) ? HeapAlloc(GetProcessHeap(), 0, ParametersSize) : nullptr;
+                    if (ParametersSize > 0 && pParameters == nullptr)
+                    {
+                        hr = E_OUTOFMEMORY;
+                    }
+                    auto pParameters_1_0 = static_cast<D3D12_ROOT_PARAMETER*>(pParameters);
+
+                    if (SUCCEEDED(hr))
+                    {
+                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)
+                        {
+                            __analysis_assume(ParametersSize == sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters);
+                            pParameters_1_0[n].ParameterType = desc_1_1.pParameters[n].ParameterType;
+                            pParameters_1_0[n].ShaderVisibility = desc_1_1.pParameters[n].ShaderVisibility;
+
+                            switch (desc_1_1.pParameters[n].ParameterType)
+                            {
+                            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                                pParameters_1_0[n].Constants.Num32BitValues = desc_1_1.pParameters[n].Constants.Num32BitValues;
+                                pParameters_1_0[n].Constants.RegisterSpace = desc_1_1.pParameters[n].Constants.RegisterSpace;
+                                pParameters_1_0[n].Constants.ShaderRegister = desc_1_1.pParameters[n].Constants.ShaderRegister;
+                                break;
+
+                            case D3D12_ROOT_PARAMETER_TYPE_CBV:
+                            case D3D12_ROOT_PARAMETER_TYPE_SRV:
+                            case D3D12_ROOT_PARAMETER_TYPE_UAV:
+                                pParameters_1_0[n].Descriptor.RegisterSpace = desc_1_1.pParameters[n].Descriptor.RegisterSpace;
+                                pParameters_1_0[n].Descriptor.ShaderRegister = desc_1_1.pParameters[n].Descriptor.ShaderRegister;
+                                break;
+
+                            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                                const D3D12_ROOT_DESCRIPTOR_TABLE1& table_1_1 = desc_1_1.pParameters[n].DescriptorTable;
+
+                                const SIZE_T DescriptorRangesSize = sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges;
+                                void* pDescriptorRanges = (DescriptorRangesSize > 0 && SUCCEEDED(hr)) ? HeapAlloc(GetProcessHeap(), 0, DescriptorRangesSize) : nullptr;
+                                if (DescriptorRangesSize > 0 && pDescriptorRanges == nullptr)
+                                {
+                                    hr = E_OUTOFMEMORY;
+                                }
+                                auto pDescriptorRanges_1_0 = static_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges);
+
+                                if (SUCCEEDED(hr))
+                                {
+                                    for (UINT x = 0; x < table_1_1.NumDescriptorRanges; x++)
+                                    {
+                                        __analysis_assume(DescriptorRangesSize == sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges);
+                                        pDescriptorRanges_1_0[x].BaseShaderRegister = table_1_1.pDescriptorRanges[x].BaseShaderRegister;
+                                        pDescriptorRanges_1_0[x].NumDescriptors = table_1_1.pDescriptorRanges[x].NumDescriptors;
+                                        pDescriptorRanges_1_0[x].OffsetInDescriptorsFromTableStart = table_1_1.pDescriptorRanges[x].OffsetInDescriptorsFromTableStart;
+                                        pDescriptorRanges_1_0[x].RangeType = table_1_1.pDescriptorRanges[x].RangeType;
+                                        pDescriptorRanges_1_0[x].RegisterSpace = table_1_1.pDescriptorRanges[x].RegisterSpace;
+                                    }
+                                }
+
+                                D3D12_ROOT_DESCRIPTOR_TABLE& table_1_0 = pParameters_1_0[n].DescriptorTable;
+                                table_1_0.NumDescriptorRanges = table_1_1.NumDescriptorRanges;
+                                table_1_0.pDescriptorRanges = pDescriptorRanges_1_0;
+                            }
+                        }
+                    }
+
+                    D3D12_STATIC_SAMPLER_DESC* pStaticSamplers = nullptr;
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+                    if (desc_1_1.NumStaticSamplers > 0 && pRootSignatureDesc->Version == D3D_ROOT_SIGNATURE_VERSION_1_2)
+                    {
+                        const SIZE_T SamplersSize = sizeof(D3D12_STATIC_SAMPLER_DESC) * desc_1_1.NumStaticSamplers;
+                        pStaticSamplers = static_cast<D3D12_STATIC_SAMPLER_DESC*>(HeapAlloc(GetProcessHeap(), 0, SamplersSize));
+
+                        if (pStaticSamplers == nullptr)
+                        {
+                            hr = E_OUTOFMEMORY;
+                        }
+                        else
+                        {
+                            const D3D12_ROOT_SIGNATURE_DESC2& desc_1_2 = pRootSignatureDesc->Desc_1_2;
+                            for (UINT n = 0; n < desc_1_1.NumStaticSamplers; ++n)
+                            {
+                                if ((desc_1_2.pStaticSamplers[n].Flags & ~D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR) != 0)
+                                {
+                                    hr = E_INVALIDARG;
+                                    break;
+                                }
+                                memcpy(pStaticSamplers + n, desc_1_2.pStaticSamplers + n, sizeof(D3D12_STATIC_SAMPLER_DESC));
+                            }
+                        }
+                    }
+#endif
+
+                    if (SUCCEEDED(hr))
+                    {
+                        const CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags);
+                        hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);
+                    }
+
+                    if (pParameters)
+                    {
+                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)
+                        {
+                            if (desc_1_1.pParameters[n].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+                            {
+                                auto pDescriptorRanges_1_0 = pParameters_1_0[n].DescriptorTable.pDescriptorRanges;
+                                HeapFree(GetProcessHeap(), 0, reinterpret_cast<void*>(const_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges_1_0)));
+                            }
+                        }
+                        HeapFree(GetProcessHeap(), 0, pParameters);
+                    }
+
+                    if (pStaticSamplers)
+                    {
+                        HeapFree(GetProcessHeap(), 0, pStaticSamplers);
+                    }
+
+                    return hr;
+                }
+            }
+            break;
+
+        case D3D_ROOT_SIGNATURE_VERSION_1_1:
+            switch (pRootSignatureDesc->Version)
+            {
+            case D3D_ROOT_SIGNATURE_VERSION_1_0:
+            case D3D_ROOT_SIGNATURE_VERSION_1_1:
+                return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob);
+
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+            case D3D_ROOT_SIGNATURE_VERSION_1_2:
+            {
+                HRESULT hr = S_OK;
+                const D3D12_ROOT_SIGNATURE_DESC1& desc_1_1 = pRootSignatureDesc->Desc_1_1;
+
+                D3D12_STATIC_SAMPLER_DESC* pStaticSamplers = nullptr;
+                if (desc_1_1.NumStaticSamplers > 0)
+                {
+                    const SIZE_T SamplersSize = sizeof(D3D12_STATIC_SAMPLER_DESC) * desc_1_1.NumStaticSamplers;
+                    pStaticSamplers = static_cast<D3D12_STATIC_SAMPLER_DESC*>(HeapAlloc(GetProcessHeap(), 0, SamplersSize));
+
+                    if (pStaticSamplers == nullptr)
+                    {
+                        hr = E_OUTOFMEMORY;
+                    }
+                    else
+                    {
+                        const D3D12_ROOT_SIGNATURE_DESC2& desc_1_2 = pRootSignatureDesc->Desc_1_2;
+                        for (UINT n = 0; n < desc_1_1.NumStaticSamplers; ++n)
+                        {
+                            if ((desc_1_2.pStaticSamplers[n].Flags & ~D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR) != 0)
+                            {
+                                hr = E_INVALIDARG;
+                                break;
+                            }
+                            memcpy(pStaticSamplers + n, desc_1_2.pStaticSamplers + n, sizeof(D3D12_STATIC_SAMPLER_DESC));
+                        }
+                    }
+                }
+
+                if (SUCCEEDED(hr))
+                {
+                    const CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc(desc_1_1.NumParameters, desc_1_1.pParameters, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags);
+                    hr = D3D12SerializeVersionedRootSignature(&desc, ppBlob, ppErrorBlob);
+                }
+
+                if (pStaticSamplers)
+                {
+                    HeapFree(GetProcessHeap(), 0, pStaticSamplers);
+                }
+
+                return hr;
+            }
+#endif
+
+            }
+#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609)
+        case D3D_ROOT_SIGNATURE_VERSION_1_2:
+#endif
+            return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob);
+    }
+
+    return E_INVALIDARG;
+}

+ 790 - 0
thirdparty/directx_headers/include/directx/d3dx12_state_object.h

@@ -0,0 +1,790 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License (MIT).
+//
+//*********************************************************
+
+#pragma once
+
+#ifndef __cplusplus
+#error D3DX12 requires C++
+#endif
+
+#include "d3d12.h"
+
+//================================================================================================
+// D3DX12 State Object Creation Helpers
+//
+// Helper classes for creating new style state objects out of an arbitrary set of subobjects.
+// Uses STL
+//
+// Start by instantiating CD3DX12_STATE_OBJECT_DESC (see its public methods).
+// One of its methods is CreateSubobject(), which has a comment showing a couple of options for
+// defining subobjects using the helper classes for each subobject (CD3DX12_DXIL_LIBRARY_SUBOBJECT
+// etc.). The subobject helpers each have methods specific to the subobject for configuring its
+// contents.
+//
+//================================================================================================
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+#ifndef D3DX12_USE_ATL
+#include <wrl/client.h>
+#define D3DX12_COM_PTR Microsoft::WRL::ComPtr
+#define D3DX12_COM_PTR_GET(x) x.Get()
+#define D3DX12_COM_PTR_ADDRESSOF(x) x.GetAddressOf()
+#else
+#include <atlbase.h>
+#define D3DX12_COM_PTR ATL::CComPtr
+#define D3DX12_COM_PTR_GET(x) x.p
+#define D3DX12_COM_PTR_ADDRESSOF(x) &x.p
+#endif
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_STATE_OBJECT_DESC
+{
+public:
+    CD3DX12_STATE_OBJECT_DESC() noexcept
+    {
+        Init(D3D12_STATE_OBJECT_TYPE_COLLECTION);
+    }
+    CD3DX12_STATE_OBJECT_DESC(D3D12_STATE_OBJECT_TYPE Type) noexcept
+    {
+        Init(Type);
+    }
+    void SetStateObjectType(D3D12_STATE_OBJECT_TYPE Type) noexcept { m_Desc.Type = Type; }
+    operator const D3D12_STATE_OBJECT_DESC&()
+    {
+        // Do final preparation work
+        m_RepointedAssociations.clear();
+        m_SubobjectArray.clear();
+        m_SubobjectArray.reserve(m_Desc.NumSubobjects);
+        // Flatten subobjects into an array (each flattened subobject still has a
+        // member that's a pointer to its desc that's not flattened)
+        for (auto Iter = m_SubobjectList.begin();
+            Iter != m_SubobjectList.end(); Iter++)
+        {
+            m_SubobjectArray.push_back(*Iter);
+            // Store new location in array so we can redirect pointers contained in subobjects
+            Iter->pSubobjectArrayLocation = &m_SubobjectArray.back();
+        }
+        // For subobjects with pointer fields, create a new copy of those subobject definitions
+        // with fixed pointers
+        for (UINT i = 0; i < m_Desc.NumSubobjects; i++)
+        {
+            if (m_SubobjectArray[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
+            {
+                auto pOriginalSubobjectAssociation =
+                    static_cast<const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION*>(m_SubobjectArray[i].pDesc);
+                D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation;
+                auto pWrapper =
+                    static_cast<const SUBOBJECT_WRAPPER*>(pOriginalSubobjectAssociation->pSubobjectToAssociate);
+                Repointed.pSubobjectToAssociate = pWrapper->pSubobjectArrayLocation;
+                m_RepointedAssociations.push_back(Repointed);
+                m_SubobjectArray[i].pDesc = &m_RepointedAssociations.back();
+            }
+        }
+        // Below: using ugly way to get pointer in case .data() is not defined
+        m_Desc.pSubobjects = m_Desc.NumSubobjects ? &m_SubobjectArray[0] : nullptr;
+        return m_Desc;
+    }
+    operator const D3D12_STATE_OBJECT_DESC*()
+    {
+        // Cast calls the above final preparation work
+        return &static_cast<const D3D12_STATE_OBJECT_DESC&>(*this);
+    }
+
+    // CreateSubobject creates a sububject helper (e.g. CD3DX12_HIT_GROUP_SUBOBJECT)
+    // whose lifetime is owned by this class.
+    // e.g.
+    //
+    //    CD3DX12_STATE_OBJECT_DESC Collection1(D3D12_STATE_OBJECT_TYPE_COLLECTION);
+    //    auto Lib0 = Collection1.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>();
+    //    Lib0->SetDXILLibrary(&pMyAppDxilLibs[0]);
+    //    Lib0->DefineExport(L"rayGenShader0"); // in practice these export listings might be
+    //                                          // data/engine driven
+    //    etc.
+    //
+    // Alternatively, users can instantiate sububject helpers explicitly, such as via local
+    // variables instead, passing the state object desc that should point to it into the helper
+    // constructor (or call mySubobjectHelper.AddToStateObject(Collection1)).
+    // In this alternative scenario, the user must keep the subobject alive as long as the state
+    // object it is associated with is alive, else its pointer references will be stale.
+    // e.g.
+    //
+    //    CD3DX12_STATE_OBJECT_DESC RaytracingState2(D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);
+    //    CD3DX12_DXIL_LIBRARY_SUBOBJECT LibA(RaytracingState2);
+    //    LibA.SetDXILLibrary(&pMyAppDxilLibs[4]); // not manually specifying exports
+    //                                             // - meaning all exports in the libraries
+    //                                             // are exported
+    //    etc.
+
+    template<typename T>
+    T* CreateSubobject()
+    {
+        T* pSubobject = new T(*this);
+        m_OwnedSubobjectHelpers.emplace_back(pSubobject);
+        return pSubobject;
+    }
+
+private:
+    D3D12_STATE_SUBOBJECT* TrackSubobject(D3D12_STATE_SUBOBJECT_TYPE Type, void* pDesc)
+    {
+        SUBOBJECT_WRAPPER Subobject;
+        Subobject.pSubobjectArrayLocation = nullptr;
+        Subobject.Type = Type;
+        Subobject.pDesc = pDesc;
+        m_SubobjectList.push_back(Subobject);
+        m_Desc.NumSubobjects++;
+        return &m_SubobjectList.back();
+    }
+    void Init(D3D12_STATE_OBJECT_TYPE Type) noexcept
+    {
+        SetStateObjectType(Type);
+        m_Desc.pSubobjects = nullptr;
+        m_Desc.NumSubobjects = 0;
+        m_SubobjectList.clear();
+        m_SubobjectArray.clear();
+        m_RepointedAssociations.clear();
+    }
+    typedef struct SUBOBJECT_WRAPPER : public D3D12_STATE_SUBOBJECT
+    {
+        D3D12_STATE_SUBOBJECT* pSubobjectArrayLocation; // new location when flattened into array
+                                                        // for repointing pointers in subobjects
+    } SUBOBJECT_WRAPPER;
+    D3D12_STATE_OBJECT_DESC m_Desc;
+    std::list<SUBOBJECT_WRAPPER>   m_SubobjectList; // Pointers to list nodes handed out so
+                                                    // these can be edited live
+    std::vector<D3D12_STATE_SUBOBJECT> m_SubobjectArray; // Built at the end, copying list contents
+
+    std::list<D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION>
+            m_RepointedAssociations; // subobject type that contains pointers to other subobjects,
+                                     // repointed to flattened array
+
+    class StringContainer
+    {
+    public:
+        LPCWSTR LocalCopy(LPCWSTR string, bool bSingleString = false)
+        {
+            if (string)
+            {
+                if (bSingleString)
+                {
+                    m_Strings.clear();
+                    m_Strings.push_back(string);
+                }
+                else
+                {
+                    m_Strings.push_back(string);
+                }
+                return m_Strings.back().c_str();
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+        void clear() noexcept { m_Strings.clear(); }
+    private:
+        std::list<std::wstring> m_Strings;
+    };
+
+    class SUBOBJECT_HELPER_BASE
+    {
+    public:
+        SUBOBJECT_HELPER_BASE() noexcept { Init(); }
+        virtual ~SUBOBJECT_HELPER_BASE() = default;
+        virtual D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept = 0;
+        void AddToStateObject(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+        {
+            m_pSubobject = ContainingStateObject.TrackSubobject(Type(), Data());
+        }
+    protected:
+        virtual void* Data() noexcept = 0;
+        void Init() noexcept { m_pSubobject = nullptr; }
+        D3D12_STATE_SUBOBJECT* m_pSubobject;
+    };
+
+#if(__cplusplus >= 201103L)
+    std::list<std::unique_ptr<const SUBOBJECT_HELPER_BASE>> m_OwnedSubobjectHelpers;
+#else
+    class OWNED_HELPER
+    {
+    public:
+        OWNED_HELPER(const SUBOBJECT_HELPER_BASE* pHelper) noexcept { m_pHelper = pHelper; }
+        ~OWNED_HELPER() { delete m_pHelper; }
+        const SUBOBJECT_HELPER_BASE* m_pHelper;
+    };
+
+    std::list<OWNED_HELPER> m_OwnedSubobjectHelpers;
+#endif
+
+    friend class CD3DX12_DXIL_LIBRARY_SUBOBJECT;
+    friend class CD3DX12_EXISTING_COLLECTION_SUBOBJECT;
+    friend class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT;
+    friend class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
+    friend class CD3DX12_HIT_GROUP_SUBOBJECT;
+    friend class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT;
+    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT;
+    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT;
+    friend class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT;
+    friend class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT;
+    friend class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT;
+    friend class CD3DX12_NODE_MASK_SUBOBJECT;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_DXIL_LIBRARY_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_DXIL_LIBRARY_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_DXIL_LIBRARY_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetDXILLibrary(const D3D12_SHADER_BYTECODE* pCode) noexcept
+    {
+        static const D3D12_SHADER_BYTECODE Default = {};
+        m_Desc.DXILLibrary = pCode ? *pCode : Default;
+    }
+    void DefineExport(
+        LPCWSTR Name,
+        LPCWSTR ExportToRename = nullptr,
+        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)
+    {
+        D3D12_EXPORT_DESC Export;
+        Export.Name = m_Strings.LocalCopy(Name);
+        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);
+        Export.Flags = Flags;
+        m_Exports.push_back(Export);
+        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
+        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());
+    }
+    template<size_t N>
+    void DefineExports(LPCWSTR(&Exports)[N])
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            DefineExport(Exports[i]);
+        }
+    }
+    void DefineExports(const LPCWSTR* Exports, UINT N)
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            DefineExport(Exports[i]);
+        }
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_DXIL_LIBRARY_DESC&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+        m_Strings.clear();
+        m_Exports.clear();
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_DXIL_LIBRARY_DESC m_Desc;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
+    std::vector<D3D12_EXPORT_DESC> m_Exports;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_EXISTING_COLLECTION_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_EXISTING_COLLECTION_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_EXISTING_COLLECTION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetExistingCollection(ID3D12StateObject*pExistingCollection) noexcept
+    {
+        m_Desc.pExistingCollection = pExistingCollection;
+        m_CollectionRef = pExistingCollection;
+    }
+    void DefineExport(
+        LPCWSTR Name,
+        LPCWSTR ExportToRename = nullptr,
+        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)
+    {
+        D3D12_EXPORT_DESC Export;
+        Export.Name = m_Strings.LocalCopy(Name);
+        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);
+        Export.Flags = Flags;
+        m_Exports.push_back(Export);
+        m_Desc.pExports = &m_Exports[0]; // using ugly way to get pointer in case .data() is not defined
+        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());
+    }
+    template<size_t N>
+    void DefineExports(LPCWSTR(&Exports)[N])
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            DefineExport(Exports[i]);
+        }
+    }
+    void DefineExports(const LPCWSTR* Exports, UINT N)
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            DefineExport(Exports[i]);
+        }
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_EXISTING_COLLECTION_DESC&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+        m_CollectionRef = nullptr;
+        m_Strings.clear();
+        m_Exports.clear();
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_EXISTING_COLLECTION_DESC m_Desc;
+    D3DX12_COM_PTR<ID3D12StateObject> m_CollectionRef;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
+    std::vector<D3D12_EXPORT_DESC> m_Exports;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetSubobjectToAssociate(const D3D12_STATE_SUBOBJECT& SubobjectToAssociate) noexcept
+    {
+        m_Desc.pSubobjectToAssociate = &SubobjectToAssociate;
+    }
+    void AddExport(LPCWSTR Export)
+    {
+        m_Desc.NumExports++;
+        m_Exports.push_back(m_Strings.LocalCopy(Export));
+        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
+    }
+    template<size_t N>
+    void AddExports(LPCWSTR (&Exports)[N])
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            AddExport(Exports[i]);
+        }
+    }
+    void AddExports(const LPCWSTR* Exports, UINT N)
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            AddExport(Exports[i]);
+        }
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+        m_Strings.clear();
+        m_Exports.clear();
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
+    std::vector<LPCWSTR> m_Exports;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION() noexcept
+    {
+        Init();
+    }
+    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetSubobjectNameToAssociate(LPCWSTR SubobjectToAssociate)
+    {
+        m_Desc.SubobjectToAssociate = m_SubobjectName.LocalCopy(SubobjectToAssociate, true);
+    }
+    void AddExport(LPCWSTR Export)
+    {
+        m_Desc.NumExports++;
+        m_Exports.push_back(m_Strings.LocalCopy(Export));
+        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined
+    }
+    template<size_t N>
+    void AddExports(LPCWSTR (&Exports)[N])
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            AddExport(Exports[i]);
+        }
+    }
+    void AddExports(const LPCWSTR* Exports, UINT N)
+    {
+        for (UINT i = 0; i < N; i++)
+        {
+            AddExport(Exports[i]);
+        }
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+        m_Strings.clear();
+        m_SubobjectName.clear();
+        m_Exports.clear();
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer m_SubobjectName;
+    std::vector<LPCWSTR> m_Exports;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_HIT_GROUP_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_HIT_GROUP_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_HIT_GROUP_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetHitGroupExport(LPCWSTR exportName)
+    {
+        m_Desc.HitGroupExport = m_Strings[0].LocalCopy(exportName, true);
+    }
+    void SetHitGroupType(D3D12_HIT_GROUP_TYPE Type) noexcept { m_Desc.Type = Type; }
+    void SetAnyHitShaderImport(LPCWSTR importName)
+    {
+        m_Desc.AnyHitShaderImport = m_Strings[1].LocalCopy(importName, true);
+    }
+    void SetClosestHitShaderImport(LPCWSTR importName)
+    {
+        m_Desc.ClosestHitShaderImport = m_Strings[2].LocalCopy(importName, true);
+    }
+    void SetIntersectionShaderImport(LPCWSTR importName)
+    {
+        m_Desc.IntersectionShaderImport = m_Strings[3].LocalCopy(importName, true);
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_HIT_GROUP_DESC&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+        for (UINT i = 0; i < m_NumStrings; i++)
+        {
+            m_Strings[i].clear();
+        }
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_HIT_GROUP_DESC m_Desc;
+    static constexpr UINT m_NumStrings = 4;
+    CD3DX12_STATE_OBJECT_DESC::StringContainer
+        m_Strings[m_NumStrings]; // one string for every entrypoint name
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void Config(UINT MaxPayloadSizeInBytes, UINT MaxAttributeSizeInBytes) noexcept
+    {
+        m_Desc.MaxPayloadSizeInBytes = MaxPayloadSizeInBytes;
+        m_Desc.MaxAttributeSizeInBytes = MaxAttributeSizeInBytes;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_RAYTRACING_SHADER_CONFIG&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_RAYTRACING_SHADER_CONFIG m_Desc;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void Config(UINT MaxTraceRecursionDepth) noexcept
+    {
+        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_RAYTRACING_PIPELINE_CONFIG&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_RAYTRACING_PIPELINE_CONFIG m_Desc;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void Config(UINT MaxTraceRecursionDepth, D3D12_RAYTRACING_PIPELINE_FLAGS Flags) noexcept
+    {
+        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;
+        m_Desc.Flags = Flags;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_RAYTRACING_PIPELINE_CONFIG1&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_RAYTRACING_PIPELINE_CONFIG1 m_Desc;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept
+    {
+        m_pRootSig = pRootSig;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator ID3D12RootSignature*() const noexcept { return D3DX12_COM_PTR_GET(m_pRootSig); }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_pRootSig = nullptr;
+    }
+    void* Data() noexcept override { return D3DX12_COM_PTR_ADDRESSOF(m_pRootSig); }
+    D3DX12_COM_PTR<ID3D12RootSignature> m_pRootSig;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept
+    {
+        m_pRootSig = pRootSig;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator ID3D12RootSignature*() const noexcept { return D3DX12_COM_PTR_GET(m_pRootSig); }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_pRootSig = nullptr;
+    }
+    void* Data() noexcept override { return D3DX12_COM_PTR_ADDRESSOF(m_pRootSig); }
+    D3DX12_COM_PTR<ID3D12RootSignature> m_pRootSig;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetFlags(D3D12_STATE_OBJECT_FLAGS Flags) noexcept
+    {
+        m_Desc.Flags = Flags;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_STATE_OBJECT_CONFIG&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_STATE_OBJECT_CONFIG m_Desc;
+};
+
+//------------------------------------------------------------------------------------------------
+class CD3DX12_NODE_MASK_SUBOBJECT
+    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE
+{
+public:
+    CD3DX12_NODE_MASK_SUBOBJECT() noexcept
+    {
+        Init();
+    }
+    CD3DX12_NODE_MASK_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)
+    {
+        Init();
+        AddToStateObject(ContainingStateObject);
+    }
+    void SetNodeMask(UINT NodeMask) noexcept
+    {
+        m_Desc.NodeMask = NodeMask;
+    }
+    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override
+    {
+        return D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK;
+    }
+    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }
+    operator const D3D12_NODE_MASK&() const noexcept { return m_Desc; }
+private:
+    void Init() noexcept
+    {
+        SUBOBJECT_HELPER_BASE::Init();
+        m_Desc = {};
+    }
+    void* Data() noexcept override { return &m_Desc; }
+    D3D12_NODE_MASK m_Desc;
+};
+
+#undef D3DX12_COM_PTR
+#undef D3DX12_COM_PTR_GET
+#undef D3DX12_COM_PTR_ADDRESSOF

+ 0 - 0
thirdparty/directx_headers/dxcore.h → thirdparty/directx_headers/include/directx/dxcore.h


+ 0 - 0
thirdparty/directx_headers/dxcore_interface.h → thirdparty/directx_headers/include/directx/dxcore_interface.h


+ 0 - 0
thirdparty/directx_headers/dxgicommon.h → thirdparty/directx_headers/include/directx/dxgicommon.h


+ 2 - 0
thirdparty/directx_headers/dxgiformat.h → thirdparty/directx_headers/include/directx/dxgiformat.h

@@ -135,6 +135,8 @@ typedef enum DXGI_FORMAT
     DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE         = 189,
     DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190,
 
+    DXGI_FORMAT_A4B4G4R4_UNORM                          = 191,
+
 
     DXGI_FORMAT_FORCE_UINT                  = 0xffffffff
 } DXGI_FORMAT;

+ 195 - 0
thirdparty/directx_headers/include/dxguids/dxguids.h

@@ -0,0 +1,195 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#ifndef __cplusplus
+#error "This header requires C++"
+#endif
+
+constexpr inline bool ConstexprIsEqualGUID(REFGUID a, REFGUID b)
+{
+    return a.Data1 == b.Data1 &&
+        a.Data2 == b.Data2 &&
+        a.Data3 == b.Data3 &&
+        a.Data4[0] == b.Data4[0] &&
+        a.Data4[1] == b.Data4[1] &&
+        a.Data4[2] == b.Data4[2] &&
+        a.Data4[3] == b.Data4[3] &&
+        a.Data4[4] == b.Data4[4] &&
+        a.Data4[5] == b.Data4[5] &&
+        a.Data4[6] == b.Data4[6] &&
+        a.Data4[7] == b.Data4[7];
+}
+
+template <typename T> GUID uuidof() = delete;
+template <typename T> GUID uuidof(T*) { return uuidof<T>(); }
+template <typename T> GUID uuidof(T**) { return uuidof<T>(); }
+template <typename T> GUID uuidof(T&) { return uuidof<T>(); }
+
+// Each COM interface (e.g. ID3D12Device) has a unique interface ID (IID) associated with it. With MSVC, the IID is defined 
+// along with the interface declaration using compiler intrinsics (__declspec(uuid(...)); the IID can then be retrieved 
+// using __uuidof. These intrinsics are not supported with all toolchains, so these helpers redefine IID values that can be 
+// used with the various adapter COM helpers (ComPtr, IID_PPV_ARGS, etc.) for Linux. IIDs are stable and cannot change, but as 
+// a precaution we statically assert the values are as expected when compiling for Windows.
+#if defined(_MSC_VER)
+#define _DXGUIDS_SUPPORT_STATIC_ASSERT_IID
+#elif defined(__CRT_UUID_DECL)
+/* match _mingw.h */
+#if __cpp_constexpr >= 200704l && __cpp_inline_variables >= 201606L
+#define _DXGUIDS_SUPPORT_STATIC_ASSERT_IID
+#endif /* __cpp_constexpr >= 200704l && __cpp_inline_variables >= 201606L */
+#endif /* _MSC_VER */
+
+#ifdef _DXGUIDS_SUPPORT_STATIC_ASSERT_IID
+#define _WINADAPTER_ASSERT_IID(InterfaceName) \
+static_assert(ConstexprIsEqualGUID(uuidof<InterfaceName>(), __uuidof(InterfaceName)), "GUID definition mismatch: "#InterfaceName);
+#else
+#define _WINADAPTER_ASSERT_IID(InterfaceName)
+#endif
+
+#ifdef __CRT_UUID_DECL
+#define WINADAPTER_IID(InterfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+template <> constexpr GUID uuidof<InterfaceName>() \
+{ \
+    return { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }; \
+} \
+__CRT_UUID_DECL(InterfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+_WINADAPTER_ASSERT_IID(InterfaceName)
+#else
+#define WINADAPTER_IID(InterfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+template <> constexpr GUID uuidof<InterfaceName>() \
+{ \
+    return { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }; \
+} \
+_WINADAPTER_ASSERT_IID(InterfaceName)
+#endif /* defined(_WIN32) && defined(__MINGW32__) */
+
+// Direct3D
+#ifdef __d3d12_h__
+WINADAPTER_IID(ID3D12Object, 0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8);
+WINADAPTER_IID(ID3D12DeviceChild, 0x905db94b, 0xa00c, 0x4140, 0x9d, 0xf5, 0x2b, 0x64, 0xca, 0x9e, 0xa3, 0x57);
+WINADAPTER_IID(ID3D12RootSignature, 0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14);
+WINADAPTER_IID(ID3D12RootSignatureDeserializer, 0x34AB647B, 0x3CC8, 0x46AC, 0x84, 0x1B, 0xC0, 0x96, 0x56, 0x45, 0xC0, 0x46);
+WINADAPTER_IID(ID3D12VersionedRootSignatureDeserializer, 0x7F91CE67, 0x090C, 0x4BB7, 0xB7, 0x8E, 0xED, 0x8F, 0xF2, 0xE3, 0x1D, 0xA0);
+WINADAPTER_IID(ID3D12Pageable, 0x63ee58fb, 0x1268, 0x4835, 0x86, 0xda, 0xf0, 0x08, 0xce, 0x62, 0xf0, 0xd6);
+WINADAPTER_IID(ID3D12Heap, 0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3);
+WINADAPTER_IID(ID3D12Resource, 0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad);
+WINADAPTER_IID(ID3D12CommandAllocator, 0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24);
+WINADAPTER_IID(ID3D12Fence, 0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76);
+WINADAPTER_IID(ID3D12Fence1, 0x433685fe, 0xe22b, 0x4ca0, 0xa8, 0xdb, 0xb5, 0xb4, 0xf4, 0xdd, 0x0e, 0x4a);
+WINADAPTER_IID(ID3D12PipelineState, 0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45);
+WINADAPTER_IID(ID3D12DescriptorHeap, 0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51);
+WINADAPTER_IID(ID3D12QueryHeap, 0x0d9658ae, 0xed45, 0x469e, 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4);
+WINADAPTER_IID(ID3D12CommandSignature, 0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1);
+WINADAPTER_IID(ID3D12CommandList, 0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5);
+WINADAPTER_IID(ID3D12GraphicsCommandList, 0x5b160d0f, 0xac1b, 0x4185, 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55);
+WINADAPTER_IID(ID3D12GraphicsCommandList1, 0x553103fb, 0x1fe7, 0x4557, 0xbb, 0x38, 0x94, 0x6d, 0x7d, 0x0e, 0x7c, 0xa7);
+WINADAPTER_IID(ID3D12GraphicsCommandList2, 0x38C3E585, 0xFF17, 0x412C, 0x91, 0x50, 0x4F, 0xC6, 0xF9, 0xD7, 0x2A, 0x28);
+WINADAPTER_IID(ID3D12CommandQueue, 0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed);
+WINADAPTER_IID(ID3D12Device, 0x189819f1, 0x1db6, 0x4b57, 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7);
+WINADAPTER_IID(ID3D12PipelineLibrary, 0xc64226a8, 0x9201, 0x46af, 0xb4, 0xcc, 0x53, 0xfb, 0x9f, 0xf7, 0x41, 0x4f);
+WINADAPTER_IID(ID3D12PipelineLibrary1, 0x80eabf42, 0x2568, 0x4e5e, 0xbd, 0x82, 0xc3, 0x7f, 0x86, 0x96, 0x1d, 0xc3);
+WINADAPTER_IID(ID3D12Device1, 0x77acce80, 0x638e, 0x4e65, 0x88, 0x95, 0xc1, 0xf2, 0x33, 0x86, 0x86, 0x3e);
+WINADAPTER_IID(ID3D12Device2, 0x30baa41e, 0xb15b, 0x475c, 0xa0, 0xbb, 0x1a, 0xf5, 0xc5, 0xb6, 0x43, 0x28);
+WINADAPTER_IID(ID3D12Device3, 0x81dadc15, 0x2bad, 0x4392, 0x93, 0xc5, 0x10, 0x13, 0x45, 0xc4, 0xaa, 0x98);
+WINADAPTER_IID(ID3D12ProtectedSession, 0xA1533D18, 0x0AC1, 0x4084, 0x85, 0xB9, 0x89, 0xA9, 0x61, 0x16, 0x80, 0x6B);
+WINADAPTER_IID(ID3D12ProtectedResourceSession, 0x6CD696F4, 0xF289, 0x40CC, 0x80, 0x91, 0x5A, 0x6C, 0x0A, 0x09, 0x9C, 0x3D);
+WINADAPTER_IID(ID3D12Device4, 0xe865df17, 0xa9ee, 0x46f9, 0xa4, 0x63, 0x30, 0x98, 0x31, 0x5a, 0xa2, 0xe5);
+WINADAPTER_IID(ID3D12LifetimeOwner, 0xe667af9f, 0xcd56, 0x4f46, 0x83, 0xce, 0x03, 0x2e, 0x59, 0x5d, 0x70, 0xa8);
+WINADAPTER_IID(ID3D12SwapChainAssistant, 0xf1df64b6, 0x57fd, 0x49cd, 0x88, 0x07, 0xc0, 0xeb, 0x88, 0xb4, 0x5c, 0x8f);
+WINADAPTER_IID(ID3D12LifetimeTracker, 0x3fd03d36, 0x4eb1, 0x424a, 0xa5, 0x82, 0x49, 0x4e, 0xcb, 0x8b, 0xa8, 0x13);
+WINADAPTER_IID(ID3D12StateObject, 0x47016943, 0xfca8, 0x4594, 0x93, 0xea, 0xaf, 0x25, 0x8b, 0x55, 0x34, 0x6d);
+WINADAPTER_IID(ID3D12StateObjectProperties, 0xde5fa827, 0x9bf9, 0x4f26, 0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60);
+WINADAPTER_IID(ID3D12Device5, 0x8b4f173b, 0x2fea, 0x4b80, 0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedDataSettings, 0x82BC481C, 0x6B9B, 0x4030, 0xAE, 0xDB, 0x7E, 0xE3, 0xD1, 0xDF, 0x1E, 0x63);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedDataSettings1, 0xDBD5AE51, 0x3317, 0x4F0A, 0xAD, 0xF9, 0x1D, 0x7C, 0xED, 0xCA, 0xAE, 0x0B);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedDataSettings2, 0x61552388, 0x01ab, 0x4008, 0xa4, 0x36, 0x83, 0xdb, 0x18, 0x95, 0x66, 0xea);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedData, 0x98931D33, 0x5AE8, 0x4791, 0xAA, 0x3C, 0x1A, 0x73, 0xA2, 0x93, 0x4E, 0x71);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedData1, 0x9727A022, 0xCF1D, 0x4DDA, 0x9E, 0xBA, 0xEF, 0xFA, 0x65, 0x3F, 0xC5, 0x06);
+WINADAPTER_IID(ID3D12DeviceRemovedExtendedData2, 0x67FC5816, 0xE4CA, 0x4915, 0xBF, 0x18, 0x42, 0x54, 0x12, 0x72, 0xDA, 0x54);
+WINADAPTER_IID(ID3D12Device6, 0xc70b221b, 0x40e4, 0x4a17, 0x89, 0xaf, 0x02, 0x5a, 0x07, 0x27, 0xa6, 0xdc);
+WINADAPTER_IID(ID3D12ProtectedResourceSession1, 0xD6F12DD6, 0x76FB, 0x406E, 0x89, 0x61, 0x42, 0x96, 0xEE, 0xFC, 0x04, 0x09);
+WINADAPTER_IID(ID3D12Device7, 0x5c014b53, 0x68a1, 0x4b9b, 0x8b, 0xd1, 0xdd, 0x60, 0x46, 0xb9, 0x35, 0x8b);
+WINADAPTER_IID(ID3D12Device8, 0x9218E6BB, 0xF944, 0x4F7E, 0xA7, 0x5C, 0xB1, 0xB2, 0xC7, 0xB7, 0x01, 0xF3);
+WINADAPTER_IID(ID3D12Resource1, 0x9D5E227A, 0x4430, 0x4161, 0x88, 0xB3, 0x3E, 0xCA, 0x6B, 0xB1, 0x6E, 0x19);
+WINADAPTER_IID(ID3D12Resource2, 0xBE36EC3B, 0xEA85, 0x4AEB, 0xA4, 0x5A, 0xE9, 0xD7, 0x64, 0x04, 0xA4, 0x95);
+WINADAPTER_IID(ID3D12Heap1, 0x572F7389, 0x2168, 0x49E3, 0x96, 0x93, 0xD6, 0xDF, 0x58, 0x71, 0xBF, 0x6D);
+WINADAPTER_IID(ID3D12GraphicsCommandList3, 0x6FDA83A7, 0xB84C, 0x4E38, 0x9A, 0xC8, 0xC7, 0xBD, 0x22, 0x01, 0x6B, 0x3D);
+WINADAPTER_IID(ID3D12MetaCommand, 0xDBB84C27, 0x36CE, 0x4FC9, 0xB8, 0x01, 0xF0, 0x48, 0xC4, 0x6A, 0xC5, 0x70);
+WINADAPTER_IID(ID3D12GraphicsCommandList4, 0x8754318e, 0xd3a9, 0x4541, 0x98, 0xcf, 0x64, 0x5b, 0x50, 0xdc, 0x48, 0x74);
+WINADAPTER_IID(ID3D12ShaderCacheSession, 0x28e2495d, 0x0f64, 0x4ae4, 0xa6, 0xec, 0x12, 0x92, 0x55, 0xdc, 0x49, 0xa8);
+WINADAPTER_IID(ID3D12Device9, 0x4c80e962, 0xf032, 0x4f60, 0xbc, 0x9e, 0xeb, 0xc2, 0xcf, 0xa1, 0xd8, 0x3c);
+WINADAPTER_IID(ID3D12Device10, 0x517f8718, 0xaa66, 0x49f9, 0xb0, 0x2b, 0xa7, 0xab, 0x89, 0xc0, 0x60, 0x31);
+WINADAPTER_IID(ID3D12Device11, 0x5405c344, 0xd457, 0x444e, 0xb4, 0xdd, 0x23, 0x66, 0xe4, 0x5a, 0xee, 0x39);
+WINADAPTER_IID(ID3D12VirtualizationGuestDevice, 0xbc66d368, 0x7373, 0x4943, 0x87, 0x57, 0xfc, 0x87, 0xdc, 0x79, 0xe4, 0x76);
+WINADAPTER_IID(ID3D12Tools, 0x7071e1f0, 0xe84b, 0x4b33, 0x97, 0x4f, 0x12, 0xfa, 0x49, 0xde, 0x65, 0xc5);
+WINADAPTER_IID(ID3D12SDKConfiguration, 0xe9eb5314, 0x33aa, 0x42b2, 0xa7, 0x18, 0xd7, 0x7f, 0x58, 0xb1, 0xf1, 0xc7);
+WINADAPTER_IID(ID3D12SDKConfiguration1, 0x8aaf9303, 0xad25, 0x48b9, 0x9a, 0x57, 0xd9, 0xc3, 0x7e, 0x00, 0x9d, 0x9f);
+WINADAPTER_IID(ID3D12DeviceFactory, 0x61f307d3, 0xd34e, 0x4e7c, 0x83, 0x74, 0x3b, 0xa4, 0xde, 0x23, 0xcc, 0xcb);
+WINADAPTER_IID(ID3D12DeviceConfiguration, 0x78dbf87b, 0xf766, 0x422b, 0xa6, 0x1c, 0xc8, 0xc4, 0x46, 0xbd, 0xb9, 0xad);
+WINADAPTER_IID(ID3D12GraphicsCommandList5, 0x55050859, 0x4024, 0x474c, 0x87, 0xf5, 0x64, 0x72, 0xea, 0xee, 0x44, 0xea);
+WINADAPTER_IID(ID3D12GraphicsCommandList6, 0xc3827890, 0xe548, 0x4cfa, 0x96, 0xcf, 0x56, 0x89, 0xa9, 0x37, 0x0f, 0x80);
+WINADAPTER_IID(ID3D12GraphicsCommandList7, 0xdd171223, 0x8b61, 0x4769, 0x90, 0xe3, 0x16, 0x0c, 0xcd, 0xe4, 0xe2, 0xc1);
+WINADAPTER_IID(ID3D12GraphicsCommandList8, 0xee936ef9, 0x599d, 0x4d28, 0x93, 0x8e, 0x23, 0xc4, 0xad, 0x05, 0xce, 0x51);
+#endif
+
+// Direct3D Video
+#ifdef __d3d12video_h__
+WINADAPTER_IID(ID3D12VideoDecoderHeap,0x0946B7C9,0xEBF6,0x4047,0xBB,0x73,0x86,0x83,0xE2,0x7D,0xBB,0x1F);
+WINADAPTER_IID(ID3D12VideoDevice,0x1F052807,0x0B46,0x4ACC,0x8A,0x89,0x36,0x4F,0x79,0x37,0x18,0xA4);
+WINADAPTER_IID(ID3D12VideoDecoder,0xC59B6BDC,0x7720,0x4074,0xA1,0x36,0x17,0xA1,0x56,0x03,0x74,0x70);
+WINADAPTER_IID(ID3D12VideoProcessor,0x304FDB32,0xBEDE,0x410A,0x85,0x45,0x94,0x3A,0xC6,0xA4,0x61,0x38);
+WINADAPTER_IID(ID3D12VideoDecodeCommandList,0x3B60536E,0xAD29,0x4E64,0xA2,0x69,0xF8,0x53,0x83,0x7E,0x5E,0x53);
+WINADAPTER_IID(ID3D12VideoProcessCommandList,0xAEB2543A,0x167F,0x4682,0xAC,0xC8,0xD1,0x59,0xED,0x4A,0x62,0x09);
+WINADAPTER_IID(ID3D12VideoDecodeCommandList1,0xD52F011B,0xB56E,0x453C,0xA0,0x5A,0xA7,0xF3,0x11,0xC8,0xF4,0x72);
+WINADAPTER_IID(ID3D12VideoProcessCommandList1,0x542C5C4D,0x7596,0x434F,0x8C,0x93,0x4E,0xFA,0x67,0x66,0xF2,0x67);
+WINADAPTER_IID(ID3D12VideoMotionEstimator,0x33FDAE0E,0x098B,0x428F,0x87,0xBB,0x34,0xB6,0x95,0xDE,0x08,0xF8);
+WINADAPTER_IID(ID3D12VideoMotionVectorHeap,0x5BE17987,0x743A,0x4061,0x83,0x4B,0x23,0xD2,0x2D,0xAE,0xA5,0x05);
+WINADAPTER_IID(ID3D12VideoDevice1,0x981611AD,0xA144,0x4C83,0x98,0x90,0xF3,0x0E,0x26,0xD6,0x58,0xAB);
+WINADAPTER_IID(ID3D12VideoEncodeCommandList,0x8455293A,0x0CBD,0x4831,0x9B,0x39,0xFB,0xDB,0xAB,0x72,0x47,0x23);
+WINADAPTER_IID(ID3D12VideoDecoder1,0x79A2E5FB,0xCCD2,0x469A,0x9F,0xDE,0x19,0x5D,0x10,0x95,0x1F,0x7E);
+WINADAPTER_IID(ID3D12VideoDecoderHeap1,0xDA1D98C5,0x539F,0x41B2,0xBF,0x6B,0x11,0x98,0xA0,0x3B,0x6D,0x26);
+WINADAPTER_IID(ID3D12VideoProcessor1,0xF3CFE615,0x553F,0x425C,0x86,0xD8,0xEE,0x8C,0x1B,0x1F,0xB0,0x1C);
+WINADAPTER_IID(ID3D12VideoExtensionCommand,0x554E41E8,0xAE8E,0x4A8C,0xB7,0xD2,0x5B,0x4F,0x27,0x4A,0x30,0xE4);
+WINADAPTER_IID(ID3D12VideoDevice2,0xF019AC49,0xF838,0x4A95,0x9B,0x17,0x57,0x94,0x37,0xC8,0xF5,0x13);
+WINADAPTER_IID(ID3D12VideoDecodeCommandList2,0x6e120880,0xc114,0x4153,0x80,0x36,0xd2,0x47,0x05,0x1e,0x17,0x29);
+WINADAPTER_IID(ID3D12VideoDecodeCommandList3,0x2aee8c37,0x9562,0x42da,0x8a,0xbf,0x61,0xef,0xeb,0x2e,0x45,0x13);
+WINADAPTER_IID(ID3D12VideoProcessCommandList2,0xdb525ae4,0x6ad6,0x473c,0xba,0xa7,0x59,0xb2,0xe3,0x70,0x82,0xe4);
+WINADAPTER_IID(ID3D12VideoProcessCommandList3,0x1a0a4ca4,0x9f08,0x40ce,0x95,0x58,0xb4,0x11,0xfd,0x26,0x66,0xff);
+WINADAPTER_IID(ID3D12VideoEncodeCommandList1,0x94971eca,0x2bdb,0x4769,0x88,0xcf,0x36,0x75,0xea,0x75,0x7e,0xbc);
+WINADAPTER_IID(ID3D12VideoEncoder,0x2E0D212D,0x8DF9,0x44A6,0xA7,0x70,0xBB,0x28,0x9B,0x18,0x27,0x37);
+WINADAPTER_IID(ID3D12VideoEncoderHeap,0x22B35D96,0x876A,0x44C0,0xB2,0x5E,0xFB,0x8C,0x9C,0x7F,0x1C,0x4A);
+WINADAPTER_IID(ID3D12VideoDevice3,0x4243ADB4,0x3A32,0x4666,0x97,0x3C,0x0C,0xCC,0x56,0x25,0xDC,0x44);
+WINADAPTER_IID(ID3D12VideoEncodeCommandList2,0x895491e2,0xe701,0x46a9,0x9a,0x1f,0x8d,0x34,0x80,0xed,0x86,0x7a);
+WINADAPTER_IID(ID3D12VideoEncodeCommandList3,0x7f027b22,0x1515,0x4e85,0xaa,0x0d,0x02,0x64,0x86,0x58,0x05,0x76);
+#endif
+
+#ifdef __d3d12sdklayers_h__
+WINADAPTER_IID(ID3D12Debug, 0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0);
+WINADAPTER_IID(ID3D12Debug1, 0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04);
+WINADAPTER_IID(ID3D12Debug2, 0x93a665c4, 0xa3b2, 0x4e5d, 0xb6, 0x92, 0xa2, 0x6a, 0xe1, 0x4e, 0x33, 0x74);
+WINADAPTER_IID(ID3D12Debug3, 0x5cf4e58f, 0xf671, 0x4ff1, 0xa5, 0x42, 0x36, 0x86, 0xe3, 0xd1, 0x53, 0xd1);
+WINADAPTER_IID(ID3D12Debug4, 0x014b816e, 0x9ec5, 0x4a2f, 0xa8, 0x45, 0xff, 0xbe, 0x44, 0x1c, 0xe1, 0x3a);
+WINADAPTER_IID(ID3D12Debug5, 0x548d6b12, 0x09fa, 0x40e0, 0x90, 0x69, 0x5d, 0xcd, 0x58, 0x9a, 0x52, 0xc9);
+WINADAPTER_IID(ID3D12Debug6, 0x82a816d6, 0x5d01, 0x4157, 0x97, 0xd0, 0x49, 0x75, 0x46, 0x3f, 0xd1, 0xed);
+WINADAPTER_IID(ID3D12DebugDevice1, 0xa9b71770, 0xd099, 0x4a65, 0xa6, 0x98, 0x3d, 0xee, 0x10, 0x02, 0x0f, 0x88);
+WINADAPTER_IID(ID3D12DebugDevice, 0x3febd6dd, 0x4973, 0x4787, 0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e);
+WINADAPTER_IID(ID3D12DebugDevice2, 0x60eccbc1, 0x378d, 0x4df1, 0x89, 0x4c, 0xf8, 0xac, 0x5c, 0xe4, 0xd7, 0xdd);
+WINADAPTER_IID(ID3D12DebugCommandQueue, 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3a);
+WINADAPTER_IID(ID3D12DebugCommandQueue1, 0x16be35a2, 0xbfd6, 0x49f2, 0xbc, 0xae, 0xea, 0xae, 0x4a, 0xff, 0x86, 0x2d);
+WINADAPTER_IID(ID3D12DebugCommandList1, 0x102ca951, 0x311b, 0x4b01, 0xb1, 0x1f, 0xec, 0xb8, 0x3e, 0x06, 0x1b, 0x37);
+WINADAPTER_IID(ID3D12DebugCommandList, 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3f);
+WINADAPTER_IID(ID3D12DebugCommandList2, 0xaeb575cf, 0x4e06, 0x48be, 0xba, 0x3b, 0xc4, 0x50, 0xfc, 0x96, 0x65, 0x2e);
+WINADAPTER_IID(ID3D12DebugCommandList3, 0x197d5e15, 0x4d37, 0x4d34, 0xaf, 0x78, 0x72, 0x4c, 0xd7, 0x0f, 0xdb, 0x1f);
+WINADAPTER_IID(ID3D12SharingContract, 0x0adf7d52, 0x929c, 0x4e61, 0xad, 0xdb, 0xff, 0xed, 0x30, 0xde, 0x66, 0xef);
+WINADAPTER_IID(ID3D12InfoQueue, 0x0742a90b, 0xc387, 0x483f, 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58);
+WINADAPTER_IID(ID3D12InfoQueue1, 0x2852dd88, 0xb484, 0x4c0c, 0xb6, 0xb1, 0x67, 0x16, 0x85, 0x00, 0xe6, 0x00);
+#endif
+
+// DXCore
+#ifdef __dxcore_interface_h__
+WINADAPTER_IID(IDXCoreAdapterFactory, 0x78ee5945, 0xc36e, 0x4b13, 0xa6, 0x69, 0x00, 0x5d, 0xd1, 0x1c, 0x0f, 0x06);
+WINADAPTER_IID(IDXCoreAdapterList, 0x526c7776, 0x40e9, 0x459b, 0xb7, 0x11, 0xf3, 0x2a, 0xd7, 0x6d, 0xfc, 0x28);
+WINADAPTER_IID(IDXCoreAdapter, 0xf0db4c7f, 0xfe5a, 0x42a2, 0xbd, 0x62, 0xf2, 0xa6, 0xcf, 0x6f, 0xc8, 0x3e);
+#endif

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů