summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPedro J. Estébanez <pedrojrulez@gmail.com>2023-12-19 12:48:02 +0100
committerPedro J. Estébanez <pedrojrulez@gmail.com>2023-12-20 19:18:08 +0100
commit12a519bae232e2e4a37a243a4050edaa0d802687 (patch)
tree0a0bdd4d2bc8ecf34b7382c08c5072bf2ee8001d
parent0567c5df9f6fbd3f3237de38b36a8474a9a9b03b (diff)
downloadredot-engine-12a519bae232e2e4a37a243a4050edaa0d802687.tar.gz
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 <7645683+bruvzg@users.noreply.github.com>
-rw-r--r--core/config/project_settings.cpp3
-rw-r--r--core/typedefs.h1
-rw-r--r--doc/classes/RenderingDevice.xml102
-rw-r--r--drivers/d3d12/SCsub36
-rw-r--r--drivers/d3d12/d3d12_context.cpp244
-rw-r--r--drivers/d3d12/d3d12_context.h133
-rw-r--r--drivers/d3d12/d3d12ma.cpp17
-rw-r--r--drivers/d3d12/rendering_device_d3d12.cpp9480
-rw-r--r--drivers/d3d12/rendering_device_d3d12.h1277
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp5491
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h858
-rw-r--r--drivers/vulkan/SCsub2
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp3350
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.h482
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp9765
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h1293
-rw-r--r--drivers/vulkan/vulkan_context.cpp307
-rw-r--r--drivers/vulkan/vulkan_context.h96
-rw-r--r--main/main.cpp4
-rw-r--r--platform/android/display_server_android.cpp124
-rw-r--r--platform/android/display_server_android.h12
-rw-r--r--platform/android/vulkan_context_android.cpp12
-rw-r--r--platform/android/vulkan_context_android.h7
-rw-r--r--platform/ios/display_server_ios.h14
-rw-r--r--platform/ios/display_server_ios.mm82
-rw-r--r--platform/ios/os_ios.h6
-rw-r--r--platform/ios/os_ios.mm6
-rw-r--r--platform/ios/vulkan_context_ios.h7
-rw-r--r--platform/ios/vulkan_context_ios.mm15
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp95
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h12
-rw-r--r--platform/linuxbsd/x11/vulkan_context_x11.cpp14
-rw-r--r--platform/linuxbsd/x11/vulkan_context_x11.h8
-rw-r--r--platform/macos/display_server_macos.h12
-rw-r--r--platform/macos/display_server_macos.mm81
-rw-r--r--platform/macos/vulkan_context_macos.h7
-rw-r--r--platform/macos/vulkan_context_macos.mm12
-rw-r--r--platform/windows/detect.py12
-rw-r--r--platform/windows/display_server_windows.cpp188
-rw-r--r--platform/windows/display_server_windows.h20
-rw-r--r--platform/windows/os_windows.h9
-rw-r--r--platform/windows/vulkan_context_win.cpp15
-rw-r--r--platform/windows/vulkan_context_win.h6
-rw-r--r--servers/rendering/renderer_rd/api_context_rd.cpp33
-rw-r--r--servers/rendering/renderer_rd/api_context_rd.h85
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp4
-rw-r--r--servers/rendering/rendering_device.cpp6661
-rw-r--r--servers/rendering/rendering_device.h1975
-rw-r--r--servers/rendering/rendering_device_binds.h2
-rw-r--r--servers/rendering/rendering_device_commons.cpp912
-rw-r--r--servers/rendering/rendering_device_commons.h921
-rw-r--r--servers/rendering/rendering_device_driver.cpp380
-rw-r--r--servers/rendering/rendering_device_driver.h687
-rw-r--r--thirdparty/README.md11
-rw-r--r--thirdparty/d3d12ma/D3D12MemAlloc.cpp24
-rw-r--r--thirdparty/directx_headers/d3dx12.h5459
-rw-r--r--thirdparty/directx_headers/include/directx/D3D12TokenizedProgramFormat.hpp2627
-rw-r--r--thirdparty/directx_headers/include/directx/d3d12.h (renamed from thirdparty/directx_headers/d3d12.h)3284
-rw-r--r--thirdparty/directx_headers/include/directx/d3d12compatibility.h (renamed from thirdparty/directx_headers/d3d12compatibility.h)0
-rw-r--r--thirdparty/directx_headers/include/directx/d3d12sdklayers.h (renamed from thirdparty/directx_headers/d3d12sdklayers.h)149
-rw-r--r--thirdparty/directx_headers/include/directx/d3d12shader.h (renamed from thirdparty/directx_headers/d3d12shader.h)0
-rw-r--r--thirdparty/directx_headers/include/directx/d3d12video.h (renamed from thirdparty/directx_headers/d3d12video.h)673
-rw-r--r--thirdparty/directx_headers/include/directx/d3dcommon.h (renamed from thirdparty/directx_headers/d3dcommon.h)1
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12.h35
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_barriers.h192
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_check_feature_support.h1107
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_core.h1535
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_default.h12
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_pipeline_state_stream.h1411
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_property_format_table.h124
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_render_pass.h102
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_resource_helpers.h602
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_root_signature.h1204
-rw-r--r--thirdparty/directx_headers/include/directx/d3dx12_state_object.h790
-rw-r--r--thirdparty/directx_headers/include/directx/dxcore.h (renamed from thirdparty/directx_headers/dxcore.h)0
-rw-r--r--thirdparty/directx_headers/include/directx/dxcore_interface.h (renamed from thirdparty/directx_headers/dxcore_interface.h)0
-rw-r--r--thirdparty/directx_headers/include/directx/dxgicommon.h (renamed from thirdparty/directx_headers/dxgicommon.h)0
-rw-r--r--thirdparty/directx_headers/include/directx/dxgiformat.h (renamed from thirdparty/directx_headers/dxgiformat.h)2
-rw-r--r--thirdparty/directx_headers/include/dxguids/dxguids.h195
80 files changed, 35323 insertions, 29605 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index bf1595b41b..6a9813fe68 100644
--- a/core/config/project_settings.cpp
+++ b/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);
diff --git a/core/typedefs.h b/core/typedefs.h
index 24c247fd38..803b2e5ae0 100644
--- a/core/typedefs.h
+++ b/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.
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 20faa70226..a841453ba0 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/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.
diff --git a/drivers/d3d12/SCsub b/drivers/d3d12/SCsub
index ce7134fb77..11ae52fd40 100644
--- a/drivers/d3d12/SCsub
+++ b/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.
diff --git a/drivers/d3d12/d3d12_context.cpp b/drivers/d3d12/d3d12_context.cpp
index 6933089208..36492b198b 100644
--- a/drivers/d3d12/d3d12_context.cpp
+++ b/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() {
diff --git a/drivers/d3d12/d3d12_context.h b/drivers/d3d12/d3d12_context.h
index 31e75affd0..ec4bc832b6 100644
--- a/drivers/d3d12/d3d12_context.h
+++ b/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();
diff --git a/drivers/d3d12/d3d12ma.cpp b/drivers/d3d12/d3d12ma.cpp
index 0ac2f71074..571ec952e7 100644
--- a/drivers/d3d12/d3d12ma.cpp
+++ b/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"
diff --git a/drivers/d3d12/rendering_device_d3d12.cpp b/drivers/d3d12/rendering_device_d3d12.cpp
deleted file mode 100644
index 839bcf6bc7..0000000000
--- a/drivers/d3d12/rendering_device_d3d12.cpp
+++ /dev/null
@@ -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);
- }
-}
diff --git a/drivers/d3d12/rendering_device_d3d12.h b/drivers/d3d12/rendering_device_d3d12.h
deleted file mode 100644
index 92ae2f78fb..0000000000
--- a/drivers/d3d12/rendering_device_d3d12.h
+++ /dev/null
@@ -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
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
new file mode 100644
index 0000000000..6a2a3c32b0
--- /dev/null
+++ b/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();
+}
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
new file mode 100644
index 0000000000..bd19572878
--- /dev/null
+++ b/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
diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub
index a076c0ac54..5e4bc986b8 100644
--- a/drivers/vulkan/SCsub
+++ b/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"
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
new file mode 100644
index 0000000000..911efa7755
--- /dev/null
+++ b/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);
+}
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h
new file mode 100644
index 0000000000..6d8f6fd0e0
--- /dev/null
+++ b/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
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
deleted file mode 100644
index 04aeac2bfc..0000000000
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ /dev/null
@@ -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);
- }
-}
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
deleted file mode 100644
index e8ad0e4f45..0000000000
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ /dev/null
@@ -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
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 7a397a170d..1b1d4fa50f 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/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);
}
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 2ccfd13739..ce1299a559 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/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();
diff --git a/main/main.cpp b/main/main.cpp
index 350b8606b9..3635fb8caf 100644
--- a/main/main.cpp
+++ b/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
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 9529e0e683..340823baac 100644
--- a/platform/android/display_server_android.cpp
+++ b/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;
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 54912212dc..80af4f00c1 100644
--- a/platform/android/display_server_android.h
+++ b/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;
diff --git a/platform/android/vulkan_context_android.cpp b/platform/android/vulkan_context_android.cpp
index 01e6d14438..4f9140bf3e 100644
--- a/platform/android/vulkan_context_android.cpp
+++ b/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));
diff --git a/platform/android/vulkan_context_android.h b/platform/android/vulkan_context_android.h
index f253149ef6..3cee3feb86 100644
--- a/platform/android/vulkan_context_android.h
+++ b/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;
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index be4ea1e6ab..3d19222fa8 100644
--- a/platform/ios/display_server_ios.h
+++ b/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;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 60da16ae8c..c31f503605 100644
--- a/platform/ios/display_server_ios.mm
+++ b/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;
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 9dc5e11497..06724d763f 100644
--- a/platform/ios/os_ios.h
+++ b/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 {
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 16ac3acbec..a646705305 100644
--- a/platform/ios/os_ios.mm
+++ b/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,
diff --git a/platform/ios/vulkan_context_ios.h b/platform/ios/vulkan_context_ios.h
index 58dad4aad6..cdc8b618af 100644
--- a/platform/ios/vulkan_context_ios.h
+++ b/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();
diff --git a/platform/ios/vulkan_context_ios.mm b/platform/ios/vulkan_context_ios.mm
index 56f1894e06..014e05f2e6 100644
--- a/platform/ios/vulkan_context_ios.mm
+++ b/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);
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index e1d842422c..cd9904db51 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/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
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index a8d134a6c7..ac2c7843f6 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/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)
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.cpp b/platform/linuxbsd/x11/vulkan_context_x11.cpp
index d240480f61..3eee1706b0 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.cpp
+++ b/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);
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.h b/platform/linuxbsd/x11/vulkan_context_x11.h
index 294fdc710e..2390326b44 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.h
+++ b/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();
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index f012292f84..1c0cfd34f4 100644
--- a/platform/macos/display_server_macos.h
+++ b/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;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 407a315827..1d93e458ed 100644
--- a/platform/macos/display_server_macos.mm
+++ b/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
diff --git a/platform/macos/vulkan_context_macos.h b/platform/macos/vulkan_context_macos.h
index ab019384e2..6205877120 100644
--- a/platform/macos/vulkan_context_macos.h
+++ b/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();
diff --git a/platform/macos/vulkan_context_macos.mm b/platform/macos/vulkan_context_macos.mm
index 46a2d9f86a..18c3bda39b 100644
--- a/platform/macos/vulkan_context_macos.mm
+++ b/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);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 4acdc8e639..801b32140a 100644
--- a/platform/windows/detect.py
+++ b/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"])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 77dfff2e5d..811d124230 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/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
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 1e61462e95..29c2460c10 100644
--- a/platform/windows/display_server_windows.h
+++ b/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;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 02f062f2de..35b88acd26 100644
--- a/platform/windows/os_windows.h
+++ b/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>
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp
index a60055dbec..69f8dc23fb 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/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);
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index 01ae2031e7..29ab1d45c3 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/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();
diff --git a/servers/rendering/renderer_rd/api_context_rd.cpp b/servers/rendering/renderer_rd/api_context_rd.cpp
new file mode 100644
index 0000000000..b5b3cdd88c
--- /dev/null
+++ b/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() {}
diff --git a/servers/rendering/renderer_rd/api_context_rd.h b/servers/rendering/renderer_rd/api_context_rd.h
new file mode 100644
index 0000000000..22167be3c1
--- /dev/null
+++ b/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
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 242b0301f1..2873269586 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/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;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 307cbd703a..380e325ffa 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/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);
}
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index c2fa232eac..a7f124c23c 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -33,17 +33,13 @@
#include "rendering_device_binds.h"
-#include "thirdparty/spirv-reflect/spirv_reflect.h"
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "servers/rendering/renderer_rd/api_context_rd.h"
-RenderingDevice *RenderingDevice::singleton = nullptr;
+//#define FORCE_FULL_BARRIER
-const char *RenderingDevice::shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = {
- "Vertex",
- "Fragment",
- "TesselationControl",
- "TesselationEvaluation",
- "Compute",
-};
+RenderingDevice *RenderingDevice::singleton = nullptr;
RenderingDevice *RenderingDevice::get_singleton() {
return singleton;
@@ -53,6 +49,50 @@ RenderingDevice::ShaderCompileToSPIRVFunction RenderingDevice::compile_to_spirv_
RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
RenderingDevice::ShaderSPIRVGetCacheKeyFunction RenderingDevice::get_spirv_cache_key_function = nullptr;
+/***************************/
+/**** ID INFRASTRUCTURE ****/
+/***************************/
+
+void RenderingDevice::_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 RenderingDevice::_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);
+ }
+}
+
void RenderingDevice::shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function) {
compile_to_spirv_function = p_function;
}
@@ -91,625 +131,5969 @@ RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData>
return shader_create_from_bytecode(bytecode);
}
-RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
- ERR_FAIL_COND_V(p_format.is_null(), RID());
- ERR_FAIL_COND_V(p_view.is_null(), RID());
- Vector<Vector<uint8_t>> data;
- for (int i = 0; i < p_data.size(); i++) {
- Vector<uint8_t> byte_slice = p_data[i];
- ERR_FAIL_COND_V(byte_slice.is_empty(), RID());
- data.push_back(byte_slice);
+/******************/
+/**** BARRIERS ****/
+/******************/
+
+void RenderingDevice::_full_barrier(bool p_sync_with_draw) {
+ // Used for debug.
+
+ RDD::MemoryBarrier mb;
+ mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ RDD::BARRIER_ACCESS_INDEX_READ_BIT |
+ RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
+ RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_HOST_READ_BIT |
+ RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
+ mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ RDD::BARRIER_ACCESS_INDEX_READ_BIT |
+ RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
+ RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_HOST_READ_BIT |
+ RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
+
+ RDD::CommandBufferID cmd_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer;
+ driver->command_pipeline_barrier(cmd_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {});
+}
+
+/***************************/
+/**** BUFFER MANAGEMENT ****/
+/***************************/
+
+RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier) {
+ Buffer *buffer = nullptr;
+ r_stages.clear();
+ r_access.clear();
+ if (vertex_buffer_owner.owns(p_buffer)) {
+ buffer = vertex_buffer_owner.get_or_null(p_buffer);
+
+ r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
+ if (buffer->usage & RDD::BUFFER_USAGE_STORAGE_BIT) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ }
+ }
+ } else if (index_buffer_owner.owns(p_buffer)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
+ r_access.set_flag(RDD::BARRIER_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_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ }
+ r_access.set_flag(RDD::BARRIER_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_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
+ }
+
+ // FIXME: Broken.
+ //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_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+
+ if (buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT)) {
+ r_stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+ r_access.set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
+ }
}
- return texture_create(p_format->base, p_view->base, data);
+ return buffer;
}
-RID RenderingDevice::_texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture) {
- ERR_FAIL_COND_V(p_view.is_null(), RID());
+Error RenderingDevice::_insert_staging_block() {
+ StagingBufferBlock block;
- return texture_create_shared(p_view->base, p_with_texture);
+ block.driver_id = driver->buffer_create(staging_buffer_block_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);
+ ERR_FAIL_COND_V(!block.driver_id, ERR_CANT_CREATE);
+
+ block.frame_used = 0;
+ block.fill_amount = 0;
+
+ staging_buffer_blocks.insert(staging_buffer_current, block);
+ return OK;
}
-RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) {
- ERR_FAIL_COND_V(p_view.is_null(), RID());
+Error RenderingDevice::_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.
- return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type);
+ 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;
}
-Ref<RDTextureFormat> RenderingDevice::_texture_get_format(RID p_rd_texture) {
- Ref<RDTextureFormat> rtf;
- rtf.instantiate();
- rtf->base = texture_get_format(p_rd_texture);
+Error RenderingDevice::_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;
- return rtf;
+ 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).
+ uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id);
+ ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);
+
+ // Copy to staging buffer.
+ memcpy(data_ptr + block_write_offset, p_data + submit_from, block_write_amount);
+
+ // Unmap.
+ driver->buffer_unmap(staging_buffer_blocks[staging_buffer_current].driver_id);
+
+ // Insert a command to copy this.
+
+ RDD::BufferCopyRegion region;
+ region.src_offset = block_write_offset;
+ region.dst_offset = submit_from + p_offset;
+ region.size = block_write_amount;
+ driver->command_copy_buffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, p_buffer->driver_id, 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;
}
-RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {
- Vector<AttachmentFormat> attachments;
- attachments.resize(p_attachments.size());
+Error RenderingDevice::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.
+ BitField<RDD::PipelineStageBits> src_stages;
+ BitField<RDD::BarrierAccessBits> src_access;
+ Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stages, src_access, 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.");
+ }
- for (int i = 0; i < p_attachments.size(); i++) {
- Ref<RDAttachmentFormat> af = p_attachments[i];
- ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
- attachments.write[i] = af->base;
+ BitField<RDD::PipelineStageBits> dst_stages;
+ BitField<RDD::BarrierAccessBits> dst_access;
+ 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_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
}
- return framebuffer_format_create(attachments, p_view_count);
+
+ Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stages, 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.
+ RDD::BufferCopyRegion region;
+ region.src_offset = p_src_offset;
+ region.dst_offset = p_dst_offset;
+ region.size = p_size;
+ driver->command_copy_buffer(frames[frame].draw_command_buffer, src_buffer->driver_id, dst_buffer->driver_id, region);
+
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
+#else
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
+ if (dst_stages.is_empty()) {
+ dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ }
+
+ // As indicated by the post barrier mask, push a new barrier.
+ RDD::BufferBarrier bb;
+ bb.buffer = dst_buffer->driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = dst_access;
+ bb.offset = p_dst_offset;
+ bb.size = p_size;
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
+ }
+#endif
+
+ return OK;
}
-RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) {
- Vector<AttachmentFormat> attachments;
- attachments.resize(p_attachments.size());
+Error RenderingDevice::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");
+
+ BitField<RDD::PipelineStageBits> dst_stages;
+ BitField<RDD::BarrierAccessBits> dst_access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ // Protect subsequent updates.
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+ Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, 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.");
+
+ 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_stages.is_empty()) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS) && p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) {
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer->driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = dst_access;
+ bb.offset = p_offset;
+ bb.size = p_size;
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
+ }
+
+#endif
+ return err;
+}
+
+Error RenderingDevice::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");
+
+ BitField<RDD::PipelineStageBits> dst_stages;
+ BitField<RDD::BarrierAccessBits> dst_access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ // Protect subsequent updates.
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stages, 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.");
+
+ driver->command_clear_buffer(frames[frame].draw_command_buffer, buffer->driver_id, p_offset, p_size);
+
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
+#else
+ if (dst_stages.is_empty()) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer->driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = dst_access;
+ bb.offset = p_offset;
+ bb.size = p_size;
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, dst_stages, {}, bb, {});
+ }
+
+#endif
+ return OK;
+}
+
+Vector<uint8_t> RenderingDevice::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.
+ BitField<RDD::PipelineStageBits> src_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
+ BitField<RDD::BarrierAccessBits> src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ // Get the vulkan buffer and the potential stage/access possible.
+ Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stages, src_access, 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.");
+ }
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // Make sure no one is using the buffer -- the "true" gets us to the same command buffer as below.
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer->driver_id;
+ bb.src_access = src_access;
+ bb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ bb.size = buffer->size;
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, bb, {});
+ }
+
+ // 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.");
+ }
+
+ RDD::BufferID tmp_buffer = driver->buffer_create(buffer->size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);
+ ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());
+
+ RDD::BufferCopyRegion region;
+ region.src_offset = p_offset;
+ region.size = p_size;
+ driver->command_copy_buffer(frames[frame].draw_command_buffer, buffer->driver_id, tmp_buffer, region);
+ // Flush everything so memory can be safely mapped.
+ _flush(true);
+
+ uint8_t *buffer_mem = driver->buffer_map(tmp_buffer);
+ ERR_FAIL_COND_V(!buffer_mem, Vector<uint8_t>());
+
+ Vector<uint8_t> buffer_data;
+ {
+ buffer_data.resize(p_size);
+ uint8_t *w = buffer_data.ptrw();
+ memcpy(w, buffer_mem, p_size);
+ }
+
+ driver->buffer_unmap(tmp_buffer);
+
+ driver->buffer_free(tmp_buffer);
+
+ return buffer_data;
+}
+
+RID RenderingDevice::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;
+ buffer.size = p_size_bytes;
+ buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_STORAGE_BIT);
+ if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {
+ buffer.usage.set_flag(RDD::BUFFER_USAGE_INDIRECT_BIT);
+ }
+ buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
+ ERR_FAIL_COND_V(!buffer.driver_id, 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);
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer.driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ bb.size = data_size;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {});
+ }
+ }
+
+ buffer_memory += buffer.size;
+
+ return storage_buffer_owner.make_rid(buffer);
+}
+
+RID RenderingDevice::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());
+
+ Buffer texture_buffer;
+ texture_buffer.size = size_bytes;
+ BitField<RDD::BufferUsageBits> usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_TEXEL_BIT);
+ texture_buffer.driver_id = driver->buffer_create(size_bytes, usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
+ ERR_FAIL_COND_V(!texture_buffer.driver_id, RID());
+
+ bool ok = driver->buffer_set_texel_format(texture_buffer.driver_id, p_format);
+ if (!ok) {
+ driver->buffer_free(texture_buffer.driver_id);
+ ERR_FAIL_V(RID());
+ }
+
+ if (p_data.size()) {
+ _buffer_update(&texture_buffer, 0, p_data.ptr(), p_data.size());
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = texture_buffer.driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ bb.size = size_bytes;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, (RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT), {}, bb, {});
+ }
+ }
+
+ buffer_memory += size_bytes;
+
+ RID id = texture_buffer_owner.make_rid(texture_buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
+}
+
+/*****************/
+/**** TEXTURE ****/
+/*****************/
+
+RID RenderingDevice::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {
+ _THREAD_SAFE_METHOD_
+
+ // Some adjustments will happen.
+ TextureFormat format = p_format;
+
+ if (format.shareable_formats.size()) {
+ ERR_FAIL_COND_V_MSG(format.shareable_formats.find(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 && 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");
+ }
+
+ ERR_FAIL_INDEX_V(format.texture_type, RDD::TEXTURE_TYPE_MAX, RID());
+
+ ERR_FAIL_COND_V_MSG(format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");
+
+ if (format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY) {
+ ERR_FAIL_COND_V_MSG(format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures");
+ }
+
+ if (format.texture_type == TEXTURE_TYPE_3D) {
+ ERR_FAIL_COND_V_MSG(format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures");
+ }
+
+ ERR_FAIL_COND_V(format.mipmaps < 1, RID());
+
+ if (format.texture_type == TEXTURE_TYPE_1D_ARRAY || format.texture_type == TEXTURE_TYPE_2D_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) {
+ ERR_FAIL_COND_V_MSG(format.array_layers < 1, RID(),
+ "Amount of layers must be equal or greater than 1 for arrays and cubemaps.");
+ ERR_FAIL_COND_V_MSG((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) && (format.array_layers % 6) != 0, RID(),
+ "Cubemap and cubemap array textures must provide a layer number that is multiple of 6");
+ } else {
+ format.array_layers = 1;
+ }
+
+ ERR_FAIL_INDEX_V(format.samples, TEXTURE_SAMPLES_MAX, RID());
+
+ format.height = format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY ? format.height : 1;
+ format.depth = format.texture_type == TEXTURE_TYPE_3D ? format.depth : 1;
+
+ uint32_t required_mipmaps = get_image_required_mipmaps(format.width, format.height, format.depth);
+
+ ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(),
+ "Too many mipmaps requested for texture format and dimensions (" + itos(format.mipmaps) + "), maximum allowed: (" + itos(required_mipmaps) + ").");
+
+ if (p_data.size()) {
+ ERR_FAIL_COND_V_MSG(!(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");
+
+ ERR_FAIL_COND_V_MSG(p_data.size() != (int)format.array_layers, RID(),
+ "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(format.array_layers) + ").");
+
+ for (uint32_t i = 0; i < format.array_layers; i++) {
+ uint32_t required_size = get_image_format_required_size(format.format, format.width, format.height, format.depth, 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.
+ bool cpu_readable = (format.usage_bits & RDD::TEXTURE_USAGE_CPU_READ_BIT);
+ BitField<RDD::TextureUsageBits> supported_usage = driver->texture_get_usages_supported_by_format(format.format, cpu_readable);
+
+ String format_text = "'" + String(FORMAT_NAMES[format.format]) + "'";
+
+ if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture.");
+ }
+ if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment.");
+ }
+ if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");
+ }
+ if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image.");
+ }
+ if ((format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");
+ }
+ if ((format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && !supported_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as VRS attachment.");
+ }
+ }
+
+ // Transfer and validate view info.
+
+ RDD::TextureView tv;
+ if (p_view.format_override == DATA_FORMAT_MAX) {
+ tv.format = format.format;
+ } else {
+ ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
+ tv.format = p_view.format_override;
+ }
+ 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());
+ tv.swizzle_r = p_view.swizzle_r;
+ tv.swizzle_g = p_view.swizzle_g;
+ tv.swizzle_b = p_view.swizzle_b;
+ tv.swizzle_a = p_view.swizzle_a;
+
+ // Create.
+
+ Texture texture;
+
+ texture.driver_id = driver->texture_create(format, tv);
+ ERR_FAIL_COND_V(!texture.driver_id, RID());
+ texture.type = format.texture_type;
+ texture.format = format.format;
+ texture.width = format.width;
+ texture.height = format.height;
+ texture.depth = format.depth;
+ texture.layers = format.array_layers;
+ texture.mipmaps = format.mipmaps;
+ texture.base_mipmap = 0;
+ texture.base_layer = 0;
+ texture.is_resolve_buffer = format.is_resolve_buffer;
+ texture.usage_flags = format.usage_bits;
+ texture.samples = format.samples;
+ texture.allowed_shared_formats = format.shareable_formats;
+
+ // Set base layout based on usage priority.
+
+ if ((format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT)) {
+ // First priority, readable.
+ texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ } else if ((format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
+ // Second priority, storage.
+ texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ } else if ((format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ // Third priority, color or depth.
+ texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ } else if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ } else {
+ texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ }
+
+ if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
+ if (format_has_stencil(format.format)) {
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);
+ }
+ } else {
+ texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
+ }
+
+ texture.bound = false;
+
+ // Barrier to set layout.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = texture.driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ tb.next_layout = texture.layout;
+ tb.subresources.aspect = texture.barrier_aspect_flags;
+ tb.subresources.mipmap_count = format.mipmaps;
+ tb.subresources.layer_count = format.array_layers;
+
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb);
+ }
+
+ texture_memory += driver->texture_get_allocation_size(texture.driver_id);
+
+ 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 < p_format.array_layers; i++) {
+ _texture_update(id, i, p_data[i], BARRIER_MASK_ALL_BARRIERS, true);
+ }
+ }
+ return id;
+}
+
+RID RenderingDevice::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_COND_V(!src_texture, RID());
+
+ if (src_texture->owner.is_valid()) { // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.
+ p_with_texture = src_texture->owner;
+ src_texture = texture_owner.get_or_null(src_texture->owner);
+ ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
+ }
+
+ // Create view.
+
+ Texture texture = *src_texture;
+
+ RDD::TextureView tv;
+ if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
+ tv.format = 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.");
+ tv.format = p_view.format_override;
+ }
+ tv.swizzle_r = p_view.swizzle_r;
+ tv.swizzle_g = p_view.swizzle_g;
+ tv.swizzle_b = p_view.swizzle_b;
+ tv.swizzle_a = p_view.swizzle_a;
+
+ texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
+ ERR_FAIL_COND_V(!texture.driver_id, RID());
+
+ 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 RenderingDevice::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, 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).
+
+ Texture texture;
+ 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_usage;
+ 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 (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT)) {
+ // First priority, readable.
+ texture.layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ } else if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT)) {
+ // Second priority, storage.
+ texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ } else if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ // Third priority, color or depth.
+ texture.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ } else if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ texture.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ } else {
+ texture.layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ }
+
+ if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT);
+ /*if (format_has_stencil(p_format.format)) {
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);
+ }*/
+ } else {
+ texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
+ texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
+ }
+
+ texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
+ ERR_FAIL_COND_V(!texture.driver_id, RID());
+
+ // Barrier to set layout.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = texture.driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ tb.next_layout = texture.layout;
+ tb.subresources.aspect = texture.barrier_aspect_flags;
+ tb.subresources.mipmap_count = texture.mipmaps;
+ tb.subresources.layer_count = texture.layers;
+
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT, {}, {}, tb);
+ }
+
+ RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+
+ return id;
+}
+
+RID RenderingDevice::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_COND_V(!src_texture, RID());
+
+ if (src_texture->owner.is_valid()) { // // Ahh this is a share. The RenderingDeviceDriver needs the actual owner.
+ p_with_texture = src_texture->owner;
+ src_texture = texture_owner.get_or_null(src_texture->owner);
+ ERR_FAIL_COND_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;
+
+ 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;
+ }
+
+ RDD::TextureView tv;
+ if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
+ tv.format = 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.");
+ tv.format = p_view.format_override;
+ }
+ tv.swizzle_r = p_view.swizzle_r;
+ tv.swizzle_g = p_view.swizzle_g;
+ tv.swizzle_b = p_view.swizzle_b;
+ tv.swizzle_a = 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.");
+ }
+
+ texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
+ ERR_FAIL_COND_V(!texture.driver_id, RID());
+
+ 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 RenderingDevice::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_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 RenderingDevice::_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 tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);
+ uint32_t required_size = tight_mip_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);
+ }
+ required_align = STEPIFY(required_align, driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_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();
+
+ RDD::CommandBufferID command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer;
+
+ // Barrier to transfer.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = texture->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.prev_layout = texture->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.subresources.aspect = texture->barrier_aspect_flags;
+ tb.subresources.mipmap_count = texture->mipmaps;
+ tb.subresources.base_layer = p_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+
+ 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 = 0;
+ 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;
+ tight_mip_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 + (tight_mip_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 block_w = 0, block_h = 0;
+ get_compressed_image_format_block_dimensions(texture->format, block_w, block_h);
+
+ uint32_t region_pitch = (region_w * pixel_size * block_w) >> get_compressed_image_format_pixel_rshift(texture->format);
+ uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);
+ region_pitch = STEPIFY(region_pitch, pitch_step);
+ uint32_t to_allocate = region_pitch * region_h;
+
+ uint32_t alloc_offset = 0, alloc_size = 0;
+ 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 = nullptr;
+ { // Map.
+ uint8_t *data_ptr = driver->buffer_map(staging_buffer_blocks[staging_buffer_current].driver_id);
+ ERR_FAIL_NULL_V(data_ptr, ERR_CANT_CREATE);
+ write_ptr = data_ptr;
+ write_ptr += alloc_offset;
+ }
+
+ 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, 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.
+ driver->buffer_unmap(staging_buffer_blocks[staging_buffer_current].driver_id);
+ }
+
+ RDD::BufferTextureCopyRegion copy_region;
+ copy_region.buffer_offset = alloc_offset;
+ copy_region.texture_subresources.aspect = texture->read_aspect_flags;
+ copy_region.texture_subresources.mipmap = mm_i;
+ copy_region.texture_subresources.base_layer = p_layer;
+ copy_region.texture_subresources.layer_count = 1;
+ copy_region.texture_offset = Vector3i(x, y, z);
+ copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);
+
+ driver->command_copy_buffer_to_texture(command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+
+ 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.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ BitField<RDD::PipelineStageBits> stages;
+ BitField<RDD::BarrierAccessBits> access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (stages.is_empty()) {
+ stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ RDD::TextureBarrier tb;
+ tb.texture = texture->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.next_layout = texture->layout;
+ tb.subresources.aspect = texture->barrier_aspect_flags;
+ tb.subresources.mipmap_count = texture->mipmaps;
+ tb.subresources.base_layer = p_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
+
+ 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> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) {
+ uint32_t width, height, depth;
+ uint32_t tight_mip_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(tight_mip_size);
+
+ 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;
+ tight_mip_size = image_total - mipmap_offset;
+
+ RDD::TextureSubresource subres;
+ subres.aspect = RDD::TEXTURE_ASPECT_COLOR;
+ subres.layer = p_layer;
+ subres.mipmap = mm_i;
+ RDD::TextureCopyableLayout layout;
+ driver->texture_get_copyable_layout(tex->driver_id, subres, &layout);
+
+ uint8_t *img_mem = driver->texture_map(tex->driver_id, subres);
+ ERR_FAIL_NULL_V(img_mem, Vector<uint8_t>());
+
+ for (uint32_t z = 0; z < depth; z++) {
+ uint8_t *write_ptr = write_ptr_mipmap + z * tight_mip_size / depth;
+ const uint8_t *slice_read_ptr = img_mem + z * layout.depth_pitch;
+
+ 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.row_pitch;
+ 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.row_pitch;
+ uint8_t *wptr = write_ptr + y * pixel_size * width;
+ memcpy(wptr, rptr, (uint64_t)pixel_size * width);
+ }
+ }
+ }
+
+ driver->texture_unmap(tex->driver_id);
+
+ mipmap_offset = image_total;
+ }
+ }
+
+ return image_data;
+}
+
+Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_layer) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_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(tex, p_layer);
+ } else {
+ LocalVector<RDD::TextureCopyableLayout> mip_layouts;
+ uint32_t work_mip_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);
+ uint32_t work_buffer_size = 0;
+ mip_layouts.resize(tex->mipmaps);
+ for (uint32_t i = 0; i < tex->mipmaps; i++) {
+ RDD::TextureSubresource subres;
+ subres.aspect = RDD::TEXTURE_ASPECT_COLOR;
+ subres.layer = p_layer;
+ subres.mipmap = i;
+ driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);
+
+ // Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.
+ DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / layer_count);
+
+ work_buffer_size = STEPIFY(work_buffer_size, work_mip_alignment) + mip_layouts[i].size;
+ }
+
+ RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);
+ ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());
+
+ RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve.
+
+ // Pre-copy barrier.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = tex->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.prev_layout = tex->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.subresources.aspect = tex->barrier_aspect_flags;
+ tb.subresources.mipmap_count = tex->mipmaps;
+ tb.subresources.base_layer = p_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+
+ {
+ uint32_t w = tex->width;
+ uint32_t h = tex->height;
+ uint32_t d = tex->depth;
+ for (uint32_t i = 0; i < tex->mipmaps; i++) {
+ RDD::BufferTextureCopyRegion copy_region;
+ copy_region.buffer_offset = mip_layouts[i].offset;
+ copy_region.texture_subresources.aspect = tex->read_aspect_flags;
+ copy_region.texture_subresources.mipmap = i;
+ copy_region.texture_subresources.base_layer = p_layer;
+ copy_region.texture_subresources.layer_count = 1;
+ copy_region.texture_region_size.x = w;
+ copy_region.texture_region_size.y = h;
+ copy_region.texture_region_size.z = d;
+ driver->command_copy_texture_to_buffer(command_buffer, tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer, copy_region);
+
+ w = MAX(1u, w >> 1);
+ h = MAX(1u, h >> 1);
+ d = MAX(1u, d >> 1);
+ }
+ }
+
+ // Post-copy barrier.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.dst_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ if ((tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT)) {
+ tb.dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.next_layout = tex->layout;
+ tb.subresources.aspect = tex->barrier_aspect_flags;
+ tb.subresources.mipmap_count = tex->mipmaps;
+ tb.subresources.base_layer = p_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, tb);
+ }
+
+ _flush(true);
+
+ const uint8_t *read_ptr = driver->buffer_map(tmp_buffer);
+ ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>());
+
+ Vector<uint8_t> buffer_data;
+ {
+ uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);
+ buffer_data.resize(tight_buffer_size);
+
+ uint8_t *write_ptr = buffer_data.ptrw();
+
+ uint32_t w = tex->width;
+ uint32_t h = tex->height;
+ uint32_t d = tex->depth;
+ for (uint32_t i = 0; i < tex->mipmaps; i++) {
+ uint32_t width = 0, height = 0, depth = 0;
+ uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);
+ uint32_t block_w = 0, block_h = 0;
+ get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
+ uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);
+
+ {
+ // Copy row-by-row to erase padding due to alignments.
+ const uint8_t *rp = read_ptr;
+ uint8_t *wp = write_ptr;
+ for (uint32_t row = h * d / block_h; row != 0; row--) {
+ memcpy(wp, rp, tight_row_pitch);
+ rp += mip_layouts[i].row_pitch;
+ wp += tight_row_pitch;
+ }
+ }
+
+ w = MAX(1u, w >> 1);
+ h = MAX(1u, h >> 1);
+ d = MAX(1u, d >> 1);
+ read_ptr += mip_layouts[i].size;
+ write_ptr += tight_mip_size;
+ }
+ }
+
+ driver->buffer_unmap(tmp_buffer);
+ driver->buffer_free(tmp_buffer);
+
+ return buffer_data;
+ }
+}
+
+bool RenderingDevice::texture_is_shared(RID p_texture) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!tex, false);
+ return tex->owner.is_valid();
+}
+
+bool RenderingDevice::texture_is_valid(RID p_texture) {
+ return texture_owner.owns(p_texture);
+}
+
+RD::TextureFormat RenderingDevice::texture_get_format(RID p_texture) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_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 RenderingDevice::texture_size(RID p_texture) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!tex, Size2i());
+ return Size2i(tex->width, tex->height);
+}
+
+#ifndef DISABLE_DEPRECATED
+uint64_t RenderingDevice::texture_get_native_handle(RID p_texture) {
+ return get_driver_resource(DRIVER_RESOURCE_TEXTURE, p_texture);
+}
+#endif
+
+Error RenderingDevice::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_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
+ "Source and destination texture must be of the same type (color or depth).");
+
+ RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
+
+ // PRE Copy the image.
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ { // Source.
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.prev_layout = src_tex->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.subresources.aspect = src_tex->barrier_aspect_flags;
+ tb.subresources.base_mipmap = p_src_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = p_src_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+ { // Dest.
+ RDD::TextureBarrier tb;
+ tb.texture = dst_tex->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.prev_layout = dst_tex->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.subresources.aspect = dst_tex->read_aspect_flags;
+ tb.subresources.base_mipmap = p_dst_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = p_dst_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+ }
+
+ // COPY.
+
+ {
+ RDD::TextureCopyRegion copy_region;
+ copy_region.src_subresources.aspect = src_tex->read_aspect_flags;
+ copy_region.src_subresources.mipmap = p_src_mipmap;
+ copy_region.src_subresources.base_layer = p_src_layer;
+ copy_region.src_subresources.layer_count = 1;
+ copy_region.src_offset = p_from;
+
+ copy_region.dst_subresources.aspect = dst_tex->read_aspect_flags;
+ copy_region.dst_subresources.mipmap = p_dst_mipmap;
+ copy_region.dst_subresources.base_layer = p_dst_layer;
+ copy_region.dst_subresources.layer_count = 1;
+ copy_region.dst_offset = p_to;
+
+ copy_region.size = p_size;
+
+ driver->command_copy_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
+ }
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // RESTORE LAYOUT for SRC and DST.
+
+ BitField<RDD::PipelineStageBits> stages;
+ BitField<RDD::BarrierAccessBits> access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (stages.is_empty()) {
+ stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ { // Restore src.
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.next_layout = src_tex->layout;
+ tb.subresources.aspect = src_tex->barrier_aspect_flags;
+ tb.subresources.base_mipmap = p_src_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = p_src_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
+ }
+
+ { // Make dst readable.
+
+ RDD::TextureBarrier tb;
+ tb.texture = dst_tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.next_layout = dst_tex->layout;
+ tb.subresources.aspect = dst_tex->read_aspect_flags;
+ tb.subresources.base_mipmap = p_dst_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = p_dst_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
+ }
+
+ 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 RenderingDevice::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_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
+ "Source and destination texture must be of the same type (color or depth).");
+
+ RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // PRE Copy the image.
+
+ { // Source.
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.prev_layout = src_tex->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.subresources.aspect = src_tex->barrier_aspect_flags;
+ tb.subresources.base_mipmap = src_tex->base_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = src_tex->base_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+ { // Dest.
+ RDD::TextureBarrier tb;
+ tb.texture = dst_tex->driver_id;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.prev_layout = dst_tex->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.subresources.aspect = dst_tex->barrier_aspect_flags;
+ tb.subresources.base_mipmap = dst_tex->base_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = dst_tex->base_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+ }
+
+ // RESOLVE.
+ driver->command_resolve_texture(command_buffer, src_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_tex->base_layer, src_tex->base_mipmap, dst_tex->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_tex->base_layer, dst_tex->base_mipmap);
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // RESTORE LAYOUT for SRC and DST.
+
+ BitField<RDD::PipelineStageBits> stages;
+ BitField<RDD::BarrierAccessBits> access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (stages.is_empty()) {
+ stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ { // Restore src.
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ tb.next_layout = src_tex->layout;
+ tb.subresources.aspect = src_tex->barrier_aspect_flags;
+ tb.subresources.base_mipmap = src_tex->base_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = src_tex->base_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, stages, {}, {}, tb);
+ }
+
+ { // Make dst readable.
+
+ RDD::TextureBarrier tb;
+ tb.texture = dst_tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ tb.next_layout = dst_tex->layout;
+ tb.subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ tb.subresources.base_mipmap = dst_tex->base_mipmap;
+ tb.subresources.mipmap_count = 1;
+ tb.subresources.base_layer = dst_tex->base_layer;
+ tb.subresources.layer_count = 1;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
+ }
+ }
+
+ return OK;
+}
+
+Error RenderingDevice::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);
+
+ RDD::CommandBufferID command_buffer = frames[frame].draw_command_buffer;
+
+ RDD::TextureLayout clear_layout = (src_tex->layout == RDD::TEXTURE_LAYOUT_GENERAL) ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_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 BitField<RDD::PipelineStageBits> valid_texture_stages = RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ constexpr BitField<RDD::BarrierAccessBits> read_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT;
+ constexpr BitField<RDD::BarrierAccessBits> read_write_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
+ const BitField<RDD::BarrierAccessBits> 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).
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.src_access = valid_texture_access;
+ tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.prev_layout = src_tex->layout;
+ tb.next_layout = clear_layout;
+ tb.subresources.aspect = src_tex->read_aspect_flags;
+ tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
+ tb.subresources.mipmap_count = p_mipmaps;
+ tb.subresources.base_layer = src_tex->base_layer + p_base_layer;
+ tb.subresources.layer_count = p_layers;
+
+ driver->command_pipeline_barrier(command_buffer, valid_texture_stages, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
+ }
+
+ RDD::TextureSubresourceRange range;
+ range.aspect = src_tex->read_aspect_flags;
+ range.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
+ range.mipmap_count = p_mipmaps;
+ range.base_layer = src_tex->base_layer + p_base_layer;
+ range.layer_count = p_layers;
+
+ driver->command_clear_color_texture(command_buffer, src_tex->driver_id, clear_layout, p_color, range);
+
+ // Barrier to post clear accesses (changing back the layout if needed).
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ BitField<RDD::PipelineStageBits> stages;
+ BitField<RDD::BarrierAccessBits> access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (stages.is_empty()) {
+ stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ RDD::TextureBarrier tb;
+ tb.texture = src_tex->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ tb.dst_access = access;
+ tb.prev_layout = clear_layout;
+ tb.next_layout = src_tex->layout;
+ tb.subresources.aspect = src_tex->read_aspect_flags;
+ tb.subresources.base_mipmap = src_tex->base_mipmap + p_base_mipmap;
+ tb.subresources.mipmap_count = p_mipmaps;
+ tb.subresources.base_layer = src_tex->base_layer + p_base_layer;
+ tb.subresources.layer_count = p_layers;
+
+ driver->command_pipeline_barrier(command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, stages, {}, {}, tb);
+
+ 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 RenderingDevice::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_
+
+ bool cpu_readable = (p_usage & RDD::TEXTURE_USAGE_CPU_READ_BIT);
+ BitField<TextureUsageBits> supported = driver->texture_get_usages_supported_by_format(p_format, cpu_readable);
+ bool any_unsupported = (((int64_t)supported) | ((int64_t)p_usage)) != ((int64_t)supported);
+ return !any_unsupported;
+}
+
+/*********************/
+/**** FRAMEBUFFER ****/
+/*********************/
+
+RDD::RenderPassID RenderingDevice::_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) {
+ // NOTE:
+ // Before the refactor to RenderingDevice-RenderingDeviceDriver, there was commented out code to
+ // specify dependencies to external subpasses. Since it had been unused for a long timel it wasn't ported
+ // to the new architecture.
+
+ LocalVector<int32_t> attachment_last_pass;
+ attachment_last_pass.resize(p_attachments.size());
+
+ if (p_view_count > 1) {
+ const RDD::MultiviewCapabilities &capabilities = driver->get_multiview_capabilities();
+
+ // This only works with multiview!
+ ERR_FAIL_COND_V_MSG(!capabilities.is_supported, RDD::RenderPassID(), "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, RDD::RenderPassID(), "Hardware does not support requested number of views for Multiview render pass");
+ }
+
+ LocalVector<RDD::Attachment> attachments;
+ LocalVector<int> attachment_remap;
for (int i = 0; i < p_attachments.size(); i++) {
- Ref<RDAttachmentFormat> af = p_attachments[i];
- ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
- attachments.write[i] = af->base;
+ if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {
+ attachment_remap.push_back(RDD::AttachmentReference::UNUSED);
+ continue;
+ }
+
+ ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, RDD::RenderPassID());
+ ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, RDD::RenderPassID());
+ 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)),
+ RDD::RenderPassID(), "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");
+
+ RDD::Attachment description;
+ description.format = p_attachments[i].format;
+ description.samples = 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.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ description.stencil_load_op = RDD::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.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
+ description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
+ description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+ } break;
+ case INITIAL_ACTION_KEEP: {
+ if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+ } break;
+ case INITIAL_ACTION_DROP: {
+ if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+ } break;
+ case INITIAL_ACTION_CLEAR_REGION_CONTINUE:
+ case INITIAL_ACTION_CONTINUE: {
+ if ((p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_LOAD;
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initial_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+ } break;
+ default: {
+ ERR_FAIL_V(RDD::RenderPassID()); // 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.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ } 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.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ } else {
+ description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencil_load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.final_layout = RDD::TEXTURE_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.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = is_sampled ? RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? RDD::TEXTURE_LAYOUT_GENERAL : RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ } else {
+ description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = RDD::TEXTURE_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.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ } else if ((p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ description.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_STORE;
+ description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ } else {
+ description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencil_store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
+ description.final_layout = RDD::TEXTURE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+
+ } break;
+ default: {
+ ERR_FAIL_V(RDD::RenderPassID()); // Should never reach here.
+ }
+ }
+ }
+
+ attachment_last_pass[i] = -1;
+ attachment_remap.push_back(attachments.size());
+ attachments.push_back(description);
}
- Vector<FramebufferPass> passes;
+ LocalVector<RDD::Subpass> subpasses;
+ subpasses.resize(p_passes.size());
+ LocalVector<RDD::SubpassDependency> subpass_dependencies;
+
for (int i = 0; i < p_passes.size(); i++) {
- Ref<RDFramebufferPass> pass = p_passes[i];
- ERR_CONTINUE(pass.is_null());
- passes.push_back(pass->base);
+ const FramebufferPass *pass = &p_passes[i];
+ RDD::Subpass &subpass = subpasses[i];
+
+ TextureSamples texture_samples = TEXTURE_SAMPLES_1;
+ bool is_multisample_first = true;
+
+ for (int j = 0; j < pass->color_attachments.size(); j++) {
+ int32_t attachment = pass->color_attachments[j];
+ RDD::AttachmentReference reference;
+ if (attachment == ATTACHMENT_UNUSED) {
+ reference.attachment = RDD::AttachmentReference::UNUSED;
+ reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ } else {
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "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), RDD::RenderPassID(), "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, RDD::RenderPassID(), "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, RDD::RenderPassID(), "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 = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ attachment_last_pass[attachment] = i;
+ }
+ reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ subpass.color_references.push_back(reference);
+ }
+
+ for (int j = 0; j < pass->input_attachments.size(); j++) {
+ int32_t attachment = pass->input_attachments[j];
+ RDD::AttachmentReference reference;
+ if (attachment == ATTACHMENT_UNUSED) {
+ reference.attachment = RDD::AttachmentReference::UNUSED;
+ reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ } else {
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "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), RDD::RenderPassID(), "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, RDD::RenderPassID(), "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 = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ attachment_last_pass[attachment] = i;
+ }
+ reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ subpass.input_references.push_back(reference);
+ }
+
+ if (pass->resolve_attachments.size() > 0) {
+ ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), RDD::RenderPassID(), "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, RDD::RenderPassID(), "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];
+ RDD::AttachmentReference reference;
+ if (attachment == ATTACHMENT_UNUSED) {
+ reference.attachment = RDD::AttachmentReference::UNUSED;
+ reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ } else {
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");
+ ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == ATTACHMENT_UNUSED, RDD::RenderPassID(), "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), RDD::RenderPassID(), "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, RDD::RenderPassID(), "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, RDD::RenderPassID(), "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
+ reference.attachment = attachment_remap[attachment];
+ reference.layout = RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ attachment_last_pass[attachment] = i;
+ }
+ reference.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ subpass.resolve_references.push_back(reference);
+ }
+
+ if (pass->depth_attachment != ATTACHMENT_UNUSED) {
+ int32_t attachment = pass->depth_attachment;
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "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), RDD::RenderPassID(), "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, RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
+ subpass.depth_stencil_reference.attachment = attachment_remap[attachment];
+ subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ 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, RDD::RenderPassID(), "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 {
+ subpass.depth_stencil_reference.attachment = RDD::AttachmentReference::UNUSED;
+ subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+ }
+
+ if (pass->vrs_attachment != ATTACHMENT_UNUSED) {
+ int32_t attachment = pass->vrs_attachment;
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "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), RDD::RenderPassID(), "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, RDD::RenderPassID(), "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
+
+ subpass.vrs_reference.attachment = attachment_remap[attachment];
+ subpass.vrs_reference.layout = RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL;
+
+ 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 == ATTACHMENT_UNUSED, RDD::RenderPassID(), "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(), RDD::RenderPassID(), "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;
+ subpasses[i].preserve_attachments.push_back(attachment);
+ }
+ }
+
+ if (r_samples) {
+ r_samples->push_back(texture_samples);
+ }
+
+ if (i > 0) {
+ RDD::SubpassDependency dependency;
+ dependency.src_subpass = i - 1;
+ dependency.dst_subpass = i;
+ dependency.src_stages = (RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+ dependency.dst_stages = (RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ dependency.src_access = (RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
+ dependency.dst_access = (RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT);
+ subpass_dependencies.push_back(dependency);
+ }
}
- return framebuffer_format_create_multipass(attachments, passes, p_view_count);
-}
+ RDD::RenderPassID render_pass = driver->render_pass_create(attachments, subpasses, subpass_dependencies, p_view_count);
+ ERR_FAIL_COND_V(!render_pass, RDD::RenderPassID());
-RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) {
- Vector<RID> textures = Variant(p_textures);
- return framebuffer_create(textures, p_format_check, p_view_count);
+ return render_pass;
}
-RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
- Vector<RID> textures = Variant(p_textures);
+RenderingDevice::FramebufferFormatID RenderingDevice::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;
- for (int i = 0; i < p_passes.size(); i++) {
- Ref<RDFramebufferPass> pass = p_passes[i];
- ERR_CONTINUE(pass.is_null());
- passes.push_back(pass->base);
+ passes.push_back(pass);
+ return framebuffer_format_create_multipass(p_format, passes, p_view_count);
+}
+RenderingDevice::FramebufferFormatID RenderingDevice::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();
}
- return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count);
+
+ Vector<TextureSamples> samples;
+ RDD::RenderPassID 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) { // 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;
}
-RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) {
- ERR_FAIL_COND_V(p_state.is_null(), RID());
+RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_empty(TextureSamples p_samples) {
+ FramebufferFormatKey key;
+ key.passes.push_back(FramebufferPass());
- return sampler_create(p_state->base);
+ const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
+ if (E) {
+ // Exists, return.
+ return E->get();
+ }
+
+ LocalVector<RDD::Subpass> subpass;
+ subpass.resize(1);
+
+ RDD::RenderPassID render_pass = driver->render_pass_create({}, subpass, {}, 1);
+ ERR_FAIL_COND_V(!render_pass, FramebufferFormatID());
+
+ 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::VertexFormatID RenderingDevice::_vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats) {
- Vector<VertexAttribute> descriptions;
- descriptions.resize(p_vertex_formats.size());
+RenderingDevice::TextureSamples RenderingDevice::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);
- for (int i = 0; i < p_vertex_formats.size(); i++) {
- Ref<RDVertexAttribute> af = p_vertex_formats[i];
- ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
- descriptions.write[i] = af->base;
+ return E->value.pass_samples[p_pass];
+}
+
+RID RenderingDevice::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 RenderingDevice::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 : ATTACHMENT_UNUSED);
+ }
+ }
}
- return vertex_format_create(descriptions);
+
+ Vector<FramebufferPass> passes;
+ passes.push_back(pass);
+
+ return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);
}
-RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets) {
- Vector<RID> buffers = Variant(p_src_buffers);
+RID RenderingDevice::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<uint64_t> offsets;
- offsets.resize(p_offsets.size());
- for (int i = 0; i < p_offsets.size(); i++) {
- offsets.write[i] = p_offsets[i];
+ 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;
}
- return vertex_array_create(p_vertex_count, p_vertex_format, buffers, offsets);
+ 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;
}
-Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {
- ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>());
+RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_get_format(RID p_framebuffer) {
+ _THREAD_SAFE_METHOD_
- Ref<RDShaderSPIRV> bytecode;
- bytecode.instantiate();
- for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
- String error;
+ Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
+ ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
- ShaderStage stage = ShaderStage(i);
- String source = p_source->get_stage_source(stage);
+ return framebuffer->format_id;
+}
- if (!source.is_empty()) {
- Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, source, p_source->get_language(), &error, p_allow_cache);
- bytecode->set_stage_bytecode(stage, spirv);
- bytecode->set_stage_compile_error(stage, error);
+bool RenderingDevice::framebuffer_is_valid(RID p_framebuffer) const {
+ _THREAD_SAFE_METHOD_
+
+ return framebuffer_owner.owns(p_framebuffer);
+}
+
+void RenderingDevice::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_COND(!framebuffer);
+
+ framebuffer->invalidated_callback = p_callback;
+ framebuffer->invalidated_callback_userdata = p_userdata;
+}
+
+/*****************/
+/**** SAMPLER ****/
+/*****************/
+
+RID RenderingDevice::sampler_create(const SamplerState &p_state) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID());
+ ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID());
+ ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID());
+ ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID());
+
+ RDD::SamplerID sampler = driver->sampler_create(p_state);
+ ERR_FAIL_COND_V(!sampler, RID());
+
+ RID id = sampler_owner.make_rid(sampler);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
+}
+
+bool RenderingDevice::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_
+
+ return driver->sampler_is_format_supported_for_filter(p_format, p_sampler_filter);
+}
+
+/***********************/
+/**** VERTEX BUFFER ****/
+/***********************/
+
+RID RenderingDevice::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;
+ buffer.size = p_size_bytes;
+ buffer.usage = RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_VERTEX_BIT;
+ if (p_use_as_storage) {
+ buffer.usage.set_flag(RDD::BUFFER_USAGE_STORAGE_BIT);
+ }
+ buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
+ ERR_FAIL_COND_V(!buffer.driver_id, 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);
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer.driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+ bb.size = data_size;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {});
}
}
- return bytecode;
+
+ buffer_memory += buffer.size;
+
+ RID id = vertex_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
-Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
- ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());
+// 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 RenderingDevice::vertex_format_create(const Vector<VertexAttribute> &p_vertex_descriptions) {
+ _THREAD_SAFE_METHOD_
- Vector<ShaderStageSPIRVData> stage_data;
- for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
- ShaderStage stage = ShaderStage(i);
- ShaderStageSPIRVData sd;
- sd.shader_stage = stage;
- String error = p_spirv->get_stage_compile_error(stage);
- ERR_FAIL_COND_V_MSG(!error.is_empty(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
- sd.spir_v = p_spirv->get_stage_bytecode(stage);
- if (sd.spir_v.is_empty()) {
- continue;
+ VertexDescriptionKey key;
+ key.vertex_formats = p_vertex_descriptions;
+
+ VertexFormatID *idptr = vertex_format_cache.getptr(key);
+ if (idptr) {
+ return *idptr;
+ }
+
+ HashSet<int> used_locations;
+ for (int i = 0; i < p_vertex_descriptions.size(); i++) {
+ ERR_CONTINUE(p_vertex_descriptions[i].format >= DATA_FORMAT_MAX);
+ ERR_FAIL_COND_V(used_locations.has(p_vertex_descriptions[i].location), INVALID_ID);
+
+ ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_descriptions[i].format) == 0, INVALID_ID,
+ "Data format for attachment (" + itos(i) + "), '" + FORMAT_NAMES[p_vertex_descriptions[i].format] + "', is not valid for a vertex array.");
+
+ used_locations.insert(p_vertex_descriptions[i].location);
+ }
+
+ RDD::VertexFormatID driver_id = driver->vertex_format_create(p_vertex_descriptions);
+ ERR_FAIL_COND_V(!driver_id, 0);
+
+ VertexFormatID id = (vertex_format_cache.size() | ((int64_t)ID_TYPE_VERTEX_FORMAT << ID_BASE_SHIFT));
+ vertex_format_cache[key] = id;
+ vertex_formats[id].vertex_formats = p_vertex_descriptions;
+ vertex_formats[id].driver_id = driver_id;
+ return id;
+}
+
+RID RenderingDevice::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);
+ }
}
- stage_data.push_back(sd);
+
+ vertex_array.buffers.push_back(buffer->driver_id);
}
- return shader_compile_binary_from_spirv(stage_data, p_shader_name);
+ 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 RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
- ERR_FAIL_COND_V(p_spirv.is_null(), RID());
+RID RenderingDevice::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.format = p_format;
+ 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
+ index_buffer.size = size_bytes;
+ index_buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_INDEX_BIT);
+ index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
+ ERR_FAIL_COND_V(!index_buffer.driver_id, 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);
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = index_buffer.driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = RDD::BARRIER_ACCESS_INDEX_READ_BIT;
+ bb.size = data_size;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT, {}, bb, {});
+ }
+ }
- Vector<ShaderStageSPIRVData> stage_data;
- for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
- ShaderStage stage = ShaderStage(i);
- ShaderStageSPIRVData sd;
- sd.shader_stage = stage;
- String error = p_spirv->get_stage_compile_error(stage);
- ERR_FAIL_COND_V_MSG(!error.is_empty(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
- sd.spir_v = p_spirv->get_stage_bytecode(stage);
- if (sd.spir_v.is_empty()) {
+ buffer_memory += index_buffer.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 RenderingDevice::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.driver_id = index_buffer->driver_id;
+ index_array.offset = p_index_offset;
+ index_array.indices = p_index_count;
+ index_array.format = index_buffer->format;
+ 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"
+};
+
+String RenderingDevice::_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->uniform_sets.size(); i++) {
+ if (p_set >= 0 && i != p_set) {
continue;
}
- stage_data.push_back(sd);
+ for (int j = 0; j < shader->uniform_sets[i].size(); j++) {
+ const ShaderUniform &ui = shader->uniform_sets[i][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 shader_create_from_spirv(stage_data);
+ return ret;
}
-RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
- Vector<Uniform> uniforms;
- uniforms.resize(p_uniforms.size());
- for (int i = 0; i < p_uniforms.size(); i++) {
- Ref<RDUniform> uniform = p_uniforms[i];
- ERR_FAIL_COND_V(!uniform.is_valid(), RID());
- uniforms.write[i] = uniform->base;
+String RenderingDevice::shader_get_binary_cache_key() const {
+ return driver->shader_get_binary_cache_key();
+}
+
+Vector<uint8_t> RenderingDevice::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
+ return driver->shader_compile_binary_from_spirv(p_spirv, p_shader_name);
+}
+
+RID RenderingDevice::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) {
+ _THREAD_SAFE_METHOD_
+
+ ShaderDescription shader_desc;
+ String name;
+ RDD::ShaderID shader_id = driver->shader_create_from_bytecode(p_shader_binary, shader_desc, name);
+ ERR_FAIL_COND_V(!shader_id, RID());
+
+ // All good, let's create modules.
+
+ RID id;
+ if (p_placeholder.is_null()) {
+ id = shader_owner.make_rid();
+ } else {
+ id = p_placeholder;
}
- return uniform_set_create(uniforms, p_shader, p_shader_set);
+
+ Shader *shader = shader_owner.get_or_null(id);
+ ERR_FAIL_NULL_V(shader, RID());
+
+ *((ShaderDescription *)shader) = shader_desc; // ShaderDescription bundle.
+ shader->name = name;
+ shader->driver_id = shader_id;
+ shader->layout_hash = driver->shader_get_layout_hash(shader_id);
+
+ for (int i = 0; i < shader->uniform_sets.size(); i++) {
+ uint32_t format = 0; // No format, default.
+
+ if (shader->uniform_sets[i].size()) {
+ // Sort and hash.
+
+ shader->uniform_sets.write[i].sort();
+
+ UniformSetFormat usformat;
+ usformat.uniforms = shader->uniform_sets[i];
+ 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->set_formats.push_back(format);
+ }
+
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
-Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
- return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
+RID RenderingDevice::shader_create_placeholder() {
+ Shader shader;
+ return shader_owner.make_rid(shader);
}
-static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
- Vector<RenderingDevice::PipelineSpecializationConstant> ret;
- ret.resize(p_constants.size());
- for (int i = 0; i < p_constants.size(); i++) {
- Ref<RDPipelineSpecializationConstant> c = p_constants[i];
- ERR_CONTINUE(c.is_null());
- RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];
- Variant value = c->get_value();
- switch (value.get_type()) {
- case Variant::BOOL: {
- sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- sc.bool_value = value;
+uint64_t RenderingDevice::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 RenderingDevice::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;
+ buffer.size = p_size_bytes;
+ buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_UNIFORM_BIT);
+ buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU);
+ ERR_FAIL_COND_V(!buffer.driver_id, 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);
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::BufferBarrier bb;
+ bb.buffer = buffer.driver_id;
+ bb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dst_access = RDD::BARRIER_ACCESS_UNIFORM_READ_BIT;
+ bb.size = data_size;
+ driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, bb, {});
+ }
+ }
+
+ buffer_memory += buffer.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 RenderingDevice::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->uniform_sets.size() || shader->uniform_sets[p_shader_set].size() == 0, RID(),
+ "Desired set (" + itos(p_shader_set) + ") not used by shader.");
+ // See that all sets in shader are satisfied.
+
+ const Vector<ShaderUniform> &set = shader->uniform_sets[p_shader_set];
+
+ uint32_t uniform_count = p_uniforms.size();
+ const Uniform *uniforms = p_uniforms.ptr();
+
+ uint32_t set_uniform_count = set.size();
+ const ShaderUniform *set_uniforms = set.ptr();
+
+ LocalVector<RDD::BoundUniform> driver_uniforms;
+ driver_uniforms.resize(set_uniform_count);
+
+ // 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 ShaderUniform &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] + "'.");
+
+ RDD::BoundUniform &driver_uniform = driver_uniforms[i];
+ driver_uniform.type = uniform.uniform_type;
+ driver_uniform.binding = uniform.binding;
+
+ 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()) + ").");
+ }
+ }
+
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j));
+ ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
+
+ driver_uniform.ids.push_back(*sampler_driver_id);
+ }
} break;
- case Variant::INT: {
- sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
- sc.int_value = value;
+ 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()) + ").");
+ }
+ }
+
+ for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
+ RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));
+ ERR_FAIL_COND_V_MSG(!sampler_driver_id, 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.");
+
+ 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)) {
+ mutable_sampled_textures.push_back(texture);
+ }
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
+
+ driver_uniform.ids.push_back(*sampler_driver_id);
+ driver_uniform.ids.push_back(texture->driver_id);
+ }
} break;
- case Variant::FLOAT: {
- sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
- sc.float_value = value;
+ 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()) + ").");
+ }
+ }
+
+ 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.");
+
+ 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)) {
+ mutable_sampled_textures.push_back(texture);
+ }
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
+
+ driver_uniform.ids.push_back(texture->driver_id);
+ }
+ } 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()) + ").");
+ }
+ }
+
+ 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.");
+
+ if ((texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT)) {
+ mutable_storage_textures.push_back(texture);
+ }
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
+
+ driver_uniform.ids.push_back(texture->driver_id);
+ }
+ } 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()) + ").");
+ }
+ }
+
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ Buffer *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.");
+
+ driver_uniform.ids.push_back(buffer->driver_id);
+ }
+ } 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()) + ").");
+ }
+ }
+
+ for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
+ RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(uniform.get_id(j + 0));
+ ERR_FAIL_COND_V_MSG(!sampler_driver_id, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
+
+ Buffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
+ ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
+
+ driver_uniform.ids.push_back(*sampler_driver_id);
+ driver_uniform.ids.push_back(buffer->driver_id);
+ }
+ } 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) + ").");
+
+ driver_uniform.ids.push_back(buffer->driver_id);
+ } 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.has_flag(RDD::BUFFER_USAGE_STORAGE_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) + ").");
+
+ driver_uniform.ids.push_back(buffer->driver_id);
+ } 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()) + ").");
+ }
+ }
+
+ 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.");
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
+
+ driver_uniform.ids.push_back(texture->driver_id);
+ }
} break;
default: {
}
}
+ }
- sc.constant_id = c->get_constant_id();
+ RDD::UniformSetID driver_uniform_set = driver->uniform_set_create(driver_uniforms, shader->driver_id, p_shader_set);
+ ERR_FAIL_COND_V(!driver_uniform_set, RID());
+
+ UniformSet uniform_set;
+ uniform_set.driver_id = driver_uniform_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));
+ }
}
- return ret;
+
+ return id;
}
-RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {
- PipelineRasterizationState rasterization_state;
- if (p_rasterization_state.is_valid()) {
- rasterization_state = p_rasterization_state->base;
+bool RenderingDevice::uniform_set_is_valid(RID p_uniform_set) {
+ return uniform_set_owner.owns(p_uniform_set);
+}
+
+void RenderingDevice::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;
+}
+
+/*******************/
+/**** PIPELINES ****/
+/*******************/
+
+RID RenderingDevice::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] != 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.");
}
- PipelineMultisampleState multisample_state;
- if (p_multisample_state.is_valid()) {
- multisample_state = p_multisample_state->base;
- for (int i = 0; i < p_multisample_state->sample_masks.size(); i++) {
- int64_t mask = p_multisample_state->sample_masks[i];
- multisample_state.sample_mask.push_back(mask);
+ RDD::VertexFormatID driver_vertex_format;
+ 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];
+ driver_vertex_format = vertex_formats[p_vertex_format].driver_id;
+
+ // Validate with inputs.
+ for (uint32_t i = 0; i < 64; i++) {
+ if (!(shader->vertex_input_mask & ((uint64_t)1) << 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 {
+ 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.");
}
- PipelineDepthStencilState depth_stencil_state;
- if (p_depth_stencil_state.is_valid()) {
- depth_stencil_state = p_depth_stencil_state->base;
+ ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());
+
+ ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());
+
+ if (p_multisample_state.sample_mask.size()) {
+ // Use sample mask.
+ ERR_FAIL_COND_V((int)TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID());
}
- PipelineColorBlendState color_blend_state;
- if (p_blend_state.is_valid()) {
- color_blend_state = p_blend_state->base;
- for (int i = 0; i < p_blend_state->attachments.size(); i++) {
- Ref<RDPipelineColorBlendStateAttachment> attachment = p_blend_state->attachments[i];
- if (attachment.is_valid()) {
- color_blend_state.attachments.push_back(attachment->base);
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID());
+
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID());
+
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID());
+ ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID());
+
+ ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID());
+
+ const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
+ ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());
+ for (int i = 0; i < pass.color_attachments.size(); i++) {
+ if (pass.color_attachments[i] != ATTACHMENT_UNUSED) {
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());
+
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());
+ }
+ }
+
+ for (int i = 0; i < shader->specialization_constants.size(); i++) {
+ const ShaderSpecializationConstant &sc = shader->specialization_constants[i];
+ for (int j = 0; j < p_specialization_constants.size(); j++) {
+ const PipelineSpecializationConstant &psc = p_specialization_constants[j];
+ if (psc.constant_id == sc.constant_id) {
+ ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");
+ break;
}
}
}
- return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants));
+ RenderPipeline pipeline;
+ pipeline.driver_id = driver->render_pipeline_create(
+ shader->driver_id,
+ driver_vertex_format,
+ p_render_primitive,
+ p_rasterization_state,
+ p_multisample_state,
+ p_depth_stencil_state,
+ p_blend_state,
+ pass.color_attachments,
+ p_dynamic_state_flags,
+ fb_format.render_pass,
+ p_for_render_pass,
+ p_specialization_constants);
+ ERR_FAIL_COND_V(!pipeline.driver_id, RID());
+
+ if (pipelines_cache_enabled) {
+ _update_pipeline_cache();
+ }
+
+ pipeline.shader = p_shader;
+ pipeline.shader_driver_id = shader->driver_id;
+ pipeline.shader_layout_hash = shader->layout_hash;
+ pipeline.set_formats = shader->set_formats;
+ 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 = p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX;
+
+ 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;
}
-RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {
- return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
+bool RenderingDevice::render_pipeline_is_valid(RID p_pipeline) {
+ _THREAD_SAFE_METHOD_
+ return render_pipeline_owner.owns(p_pipeline);
}
-RenderingDevice::DrawListID RenderingDevice::_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 TypedArray<RID> &p_storage_textures) {
- Vector<RID> stextures;
- for (int i = 0; i < p_storage_textures.size(); i++) {
- stextures.push_back(p_storage_textures[i]);
+RID RenderingDevice::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");
+
+ for (int i = 0; i < shader->specialization_constants.size(); i++) {
+ const ShaderSpecializationConstant &sc = shader->specialization_constants[i];
+ for (int j = 0; j < p_specialization_constants.size(); j++) {
+ const PipelineSpecializationConstant &psc = p_specialization_constants[j];
+ if (psc.constant_id == sc.constant_id) {
+ ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");
+ break;
+ }
+ }
}
- return draw_list_begin(p_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, stextures);
+
+ ComputePipeline pipeline;
+ pipeline.driver_id = driver->compute_pipeline_create(shader->driver_id, p_specialization_constants);
+ ERR_FAIL_COND_V(!pipeline.driver_id, RID());
+
+ if (pipelines_cache_enabled) {
+ _update_pipeline_cache();
+ }
+
+ pipeline.shader = p_shader;
+ pipeline.shader_driver_id = shader->driver_id;
+ pipeline.shader_layout_hash = shader->layout_hash;
+ pipeline.set_formats = shader->set_formats;
+ 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;
}
-Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, 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 TypedArray<RID> &p_storage_textures) {
- Vector<DrawListID> splits;
- splits.resize(p_splits);
- Vector<RID> stextures;
+bool RenderingDevice::compute_pipeline_is_valid(RID p_pipeline) {
+ return compute_pipeline_owner.owns(p_pipeline);
+}
+
+/****************/
+/**** SCREEN ****/
+/****************/
+
+int RenderingDevice::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 RenderingDevice::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 RenderingDevice::screen_get_framebuffer_format() const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
+
+ DataFormat format = driver->screen_get_format();
+ 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<RenderingDevice *>(this)->framebuffer_format_create(screen_attachment);
+}
+
+/*******************/
+/**** DRAW LIST ****/
+/*******************/
+
+RenderingDevice::DrawListID RenderingDevice::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.");
+
+ RDD::CommandBufferID 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;
+
+ RDD::RenderPassClearValue clear_value;
+ clear_value.color = p_clear_color;
+ driver->command_begin_render_pass(
+ command_buffer,
+ context->window_get_render_pass(p_screen),
+ context->window_get_framebuffer(p_screen),
+ RDD::COMMAND_BUFFER_TYPE_PRIMARY,
+ Rect2i(0, 0, size.width, size.height),
+ VectorView(&clear_value, 1));
+
+ driver->command_render_set_viewport(command_buffer, Rect2i(Point2i(), size));
+ driver->command_render_set_scissor(command_buffer, Rect2i(Point2i(), size));
+
+ return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
+}
+
+Error RenderingDevice::_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, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *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);
+
+ LocalVector<RDD::TextureID> 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->driver_id);
+ 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);
+ }
+ }
+ }
+
+ version.framebuffer = driver->framebuffer_create(version.render_pass, attachments, p_framebuffer->size.width, p_framebuffer->size.height);
+ ERR_FAIL_COND_V(!version.framebuffer, ERR_CANT_CREATE);
+
+ 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 RenderingDevice::_draw_list_render_pass_begin(Framebuffer *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_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region) {
+ LocalVector<RDD::RenderPassClearValue> clear_values;
+ clear_values.resize(p_framebuffer->texture_ids.size());
+ int clear_values_count = 0;
+ {
+ int color_index = 0;
+ for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
+ RDD::RenderPassClearValue clear_value;
+
+ Texture *texture = texture_owner.get_or_null(p_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.
+ clear_value.color = p_clear_colors[color_index];
+ color_index++;
+ } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ clear_value.depth = p_clear_depth;
+ clear_value.stencil = p_clear_stencil;
+ }
+
+ clear_values[clear_values_count++] = clear_value;
+ }
+ }
+
for (int i = 0; i < p_storage_textures.size(); i++) {
- stextures.push_back(p_storage_textures[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) {
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ // Must change layout to general.
+ RDD::TextureBarrier tb;
+ tb.texture = texture->driver_id;
+ tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ tb.prev_layout = texture->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ tb.subresources.aspect = texture->read_aspect_flags;
+ tb.subresources.base_mipmap = texture->base_mipmap;
+ tb.subresources.mipmap_count = texture->mipmaps;
+ tb.subresources.base_layer = texture->base_layer;
+ tb.subresources.layer_count = texture->layers;
+
+ driver->command_pipeline_barrier(p_command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, {}, {}, tb);
+
+ texture->layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ }
+
+ draw_list_storage_textures.push_back(p_storage_textures[i]);
+ }
}
- draw_list_begin_split(p_framebuffer, p_splits, splits.ptrw(), 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, stextures);
- Vector<int64_t> split_ids;
- split_ids.resize(splits.size());
- for (int i = 0; i < splits.size(); i++) {
- split_ids.write[i] = splits[i];
+ Rect2i region;
+ if (p_constrained_to_region) {
+ region = Rect2i(p_viewport_offset, p_viewport_size);
+ } else {
+ region = Rect2i(Point2i(), p_framebuffer->size);
}
- return split_ids;
+ driver->command_begin_render_pass(
+ p_command_buffer,
+ p_render_pass,
+ p_framebuffer_driver_id,
+ p_cmd_buffer_mode,
+ region,
+ clear_values);
+
+ // 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 < p_framebuffer->texture_ids.size(); i++) {
+ Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
+ if (!texture) {
+ continue;
+ }
+ texture->bound = true;
+ draw_list_bound_textures.push_back(p_framebuffer->texture_ids[i]);
+ }
+
+ return OK;
}
-Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {
- Vector<DrawListID> splits;
- splits.resize(p_splits);
+void RenderingDevice::_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) {
+ LocalVector<RDD::AttachmentClear> 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]);
- Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw());
- ERR_FAIL_COND_V(err != OK, Vector<int64_t>());
+ if (!texture) {
+ texture_index++;
+ continue;
+ }
- Vector<int64_t> split_ids;
- split_ids.resize(splits.size());
- for (int i = 0; i < splits.size(); i++) {
- split_ids.write[i] = splits[i];
+ RDD::AttachmentClear clear_at;
+ if (p_clear_color && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ Color clear_color = p_clear_colors[texture_index++];
+ clear_at.value.color = clear_color;
+ clear_at.color_attachment = color_index++;
+ clear_at.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
+ } else if (p_clear_depth && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ clear_at.value.depth = p_depth;
+ clear_at.value.stencil = p_stencil;
+ clear_at.color_attachment = 0;
+ clear_at.aspect = RDD::TEXTURE_ASPECT_DEPTH_BIT;
+ if (format_has_stencil(texture->format)) {
+ clear_at.aspect.set_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT);
+ }
+ } else {
+ ERR_CONTINUE(true);
+ }
+ clear_attachments.push_back(clear_at);
}
- return split_ids;
+ Rect2i rect = Rect2i(p_viewport_offset, p_viewport_size);
+
+ driver->command_render_clear_attachments(p_draw_list->command_buffer, clear_attachments, rect);
}
-void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
- ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
- draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
+RenderingDevice::DrawListID RenderingDevice::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) + ").");
+ }
+
+ RDD::FramebufferID fb_driver_id;
+ RDD::RenderPassID 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, &fb_driver_id, &render_pass, &draw_list_subpass_count);
+ ERR_FAIL_COND_V(err != OK, INVALID_ID);
+
+ RDD::CommandBufferID 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, fb_driver_id, render_pass, command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY, p_storage_textures, constrained_to_region);
+
+ if (err != OK) {
+ return INVALID_ID;
+ }
+
+ draw_list_render_pass = render_pass;
+ draw_list_vkframebuffer = fb_driver_id;
+
+ _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);
+ }
+
+ driver->command_render_set_viewport(command_buffer, Rect2i(viewport_offset, viewport_size));
+ driver->command_render_set_scissor(command_buffer, Rect2i(viewport_offset, viewport_size));
+
+ return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
}
-void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
- ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
- compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
+Error RenderingDevice::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) + ").");
+ }
+
+ RDD::FramebufferID fb_driver_id;
+ RDD::RenderPassID 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, &fb_driver_id, &render_pass, &draw_list_subpass_count);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+
+ RDD::CommandBufferID 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, fb_driver_id, render_pass, frame_command_buffer, RDD::COMMAND_BUFFER_TYPE_SECONDARY, 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 = fb_driver_id;
+
+ 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);
+ }
+
+ bool secondary_viewport_scissor = driver->api_trait_get(RDD::API_TRAIT_SECONDARY_VIEWPORT_SCISSOR);
+ for (uint32_t i = 0; i < p_splits; i++) {
+ if (secondary_viewport_scissor) {
+ driver->command_render_set_viewport(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size));
+ driver->command_render_set_scissor(draw_list[i].command_buffer, Rect2i(viewport_offset, viewport_size));
+ }
+ r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i;
+ }
+
+ return OK;
}
-Error RenderingDevice::_reflect_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, SpirvReflectionData &r_reflection_data) {
- r_reflection_data = {};
+RenderingDevice::DrawList *RenderingDevice::_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;
+ }
- for (int i = 0; i < p_spirv.size(); i++) {
- ShaderStage stage = p_spirv[i].shader_stage;
- ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage);
+ uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
- if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) {
- r_reflection_data.is_compute = true;
- ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, FAILED,
- "Compute shaders can only receive one stage, dedicated to compute.");
+ if (index >= draw_list_count) {
+ return nullptr;
}
- ERR_FAIL_COND_V_MSG(r_reflection_data.stages_mask.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].spir_v.ptr();
- SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spir_v.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_data.is_compute) {
- r_reflection_data.compute_local_size[0] = module.entry_points->local_size.x;
- r_reflection_data.compute_local_size[1] = module.entry_points->local_size.y;
- r_reflection_data.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];
-
- SpirvReflectionData::Uniform info{};
-
- 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: {
- info.type = UNIFORM_TYPE_SAMPLER;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
- info.type = UNIFORM_TYPE_TEXTURE;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
- info.type = UNIFORM_TYPE_IMAGE;
- need_array_dimensions = true;
- may_be_writable = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
- info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
- info.type = UNIFORM_TYPE_IMAGE_BUFFER;
- need_array_dimensions = true;
- may_be_writable = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
- info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
- need_block_size = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
- info.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: {
- info.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;
- }
+ return &draw_list[index];
+ } else {
+ return nullptr;
+ }
+}
- if (need_array_dimensions) {
- if (binding.array.dims_count == 0) {
- info.length = 1;
- } else {
- for (uint32_t k = 0; k < binding.array.dims_count; k++) {
- if (k == 0) {
- info.length = binding.array.dims[0];
- } else {
- info.length *= binding.array.dims[k];
- }
- }
- }
+void RenderingDevice::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
- } else if (need_block_size) {
- info.length = binding.block.size;
- } else {
- info.length = 0;
- }
+ driver->command_render_set_blend_constants(dl->command_buffer, p_color);
+}
- if (may_be_writable) {
- info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE);
- } else {
- info.writable = false;
- }
+void RenderingDevice::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
- info.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_data.uniforms.size()) {
- // Check if this already exists.
- bool exists = false;
- for (int k = 0; k < r_reflection_data.uniforms[set].size(); k++) {
- if (r_reflection_data.uniforms[set][k].binding == (uint32_t)info.binding) {
- // Already exists, verify that it's the same type.
- ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].type != info.type, FAILED,
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
-
- // Also, verify that it's the same size.
- ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].length != info.length, FAILED,
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
-
- // Also, verify that it has the same writability.
- ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].writable != info.writable, FAILED,
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability.");
-
- // Just append stage mask and return.
- r_reflection_data.uniforms.write[set].write[k].stages_mask.set_flag(stage_flag);
- exists = true;
- break;
- }
- }
+ 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 (exists) {
- continue; // Merged.
- }
- }
+ if (p_render_pipeline == dl->state.pipeline) {
+ return; // Redundant state, return.
+ }
- info.stages_mask.set_flag(stage_flag);
+ dl->state.pipeline = p_render_pipeline;
- if (set >= (uint32_t)r_reflection_data.uniforms.size()) {
- r_reflection_data.uniforms.resize(set + 1);
+ driver->command_bind_render_pipeline(dl->command_buffer, pipeline->driver_id);
+
+ if (dl->state.pipeline_shader != pipeline->shader) {
+ // Shader changed, so descriptor sets may become incompatible.
+
+ 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.
+
+ uint32_t first_invalid_set = UINT32_MAX; // All valid by default.
+ switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {
+ case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {
+ first_invalid_set = 0;
+ } break;
+ case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {
+ for (uint32_t i = 0; i < pcount; i++) {
+ if (dl->state.sets[i].pipeline_expected_format != pformats[i]) {
+ first_invalid_set = i;
+ break;
}
+ }
+ } break;
+ case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {
+ if (dl->state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {
+ first_invalid_set = 0;
+ }
+ } break;
+ }
+
+ for (uint32_t i = 0; i < pcount; i++) {
+ dl->state.sets[i].bound = i < first_invalid_set;
+ dl->state.sets[i].pipeline_expected_format = pformats[i];
+ }
+
+ 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) {
+#ifdef DEBUG_ENABLED
+ dl->validation.pipeline_push_constant_supplied = false;
+#endif
+ }
+
+ dl->state.pipeline_shader = pipeline->shader;
+ dl->state.pipeline_shader_driver_id = pipeline->shader_driver_id;
+ dl->state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;
+ }
+
+#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 RenderingDevice::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 >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,
+ "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");
+#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;
+ }
- r_reflection_data.uniforms.write[set].push_back(info);
+ dl->state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // 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;
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ 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;
}
+ }
+ }
- {
- // 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;
- SpirvReflectionData::SpecializationConstant 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_mask.set_flag(stage_flag);
-
- for (int k = 0; k < r_reflection_data.specialization_constants.size(); k++) {
- if (r_reflection_data.specialization_constants[k].constant_id == sconst.constant_id) {
- ERR_FAIL_COND_V_MSG(r_reflection_data.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_data.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;
- }
- }
+#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
+}
- if (existing > 0) {
- r_reflection_data.specialization_constants.write[existing].stages_mask.set_flag(stage_flag);
- } else {
- r_reflection_data.specialization_constants.push_back(sconst);
- }
- }
+void RenderingDevice::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;
+ driver->command_render_bind_vertex_buffers(dl->command_buffer, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr());
+}
+
+void RenderingDevice::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;
+
+ driver->command_render_bind_index_buffer(dl->command_buffer, index_array->driver_id, index_array->format, index_array->offset);
+}
+
+void RenderingDevice::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
+
+ driver->command_render_set_line_width(dl->command_buffer, p_width);
+}
+
+void RenderingDevice::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
+ driver->command_bind_push_constants(dl->command_buffer, dl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t)));
+#ifdef DEBUG_ENABLED
+ dl->validation.pipeline_push_constant_supplied = true;
+#endif
+}
+
+void RenderingDevice::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
+ driver->command_uniform_set_prepare_for_use(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i);
+ }
+ 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.
+ }
+ if (!dl->state.sets[i].bound) {
+ driver->command_bind_render_uniform_set(dl->command_buffer, dl->state.sets[i].uniform_set_driver_id, dl->state.pipeline_shader_driver_id, i);
+ 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
+ driver->command_render_draw_indexed(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
+
+ driver->command_render_draw(dl->command_buffer, to_draw, p_instances, 0, 0);
+ }
+}
+
+void RenderingDevice::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;
+ }
+
+ driver->command_render_set_scissor(dl->command_buffer, rect);
+}
+
+void RenderingDevice::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
+
+ driver->command_render_set_scissor(dl->command_buffer, dl->viewport);
+}
+
+uint32_t RenderingDevice::draw_list_get_current_pass() {
+ return draw_list_current_subpass;
+}
+
+RenderingDevice::DrawListID RenderingDevice::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_current_subpass++;
+
+ Rect2i viewport;
+ _draw_list_free(&viewport);
+
+ driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY);
+
+ _draw_list_allocate(viewport, 0, draw_list_current_subpass);
+
+ return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
+}
+Error RenderingDevice::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_current_subpass++;
+
+ Rect2i viewport;
+ _draw_list_free(&viewport);
+
+ driver->command_next_render_subpass(frames[frame].draw_command_buffer, RDD::COMMAND_BUFFER_TYPE_PRIMARY);
+
+ _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 RenderingDevice::_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++) {
+ RDD::CommandPoolID cmd_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY);
+ ERR_FAIL_COND_V(!cmd_pool, ERR_CANT_CREATE);
+ split_draw_list_allocators.write[i].command_pool = cmd_pool;
+
+ for (int j = 0; j < frame_count; j++) {
+ RDD::CommandBufferID cmd_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, cmd_pool);
+ ERR_FAIL_COND_V(!cmd_buffer, ERR_CANT_CREATE);
+ split_draw_list_allocators.write[i].command_buffers.push_back(cmd_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.
+ RDD::CommandBufferID cmd_buffer = split_draw_list_allocators[i].command_buffers[frame];
+
+ bool ok = driver->command_buffer_begin_secondary(cmd_buffer, draw_list_render_pass, p_subpass, draw_list_vkframebuffer);
+ if (!ok) {
+ memdelete_arr(draw_list);
+ draw_list = nullptr;
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+ draw_list[i].command_buffer = cmd_buffer;
+ draw_list[i].viewport = p_viewport;
+ }
+ }
+
+ return OK;
+}
- 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.");
+void RenderingDevice::_draw_list_free(Rect2i *r_last_viewport) {
+ if (draw_list_split) {
+ // Send all command buffers.
+ RDD::CommandBufferID *command_buffers = (RDD::CommandBufferID *)alloca(sizeof(RDD::CommandBufferID) * draw_list_count);
+ for (uint32_t i = 0; i < draw_list_count; i++) {
+ driver->command_buffer_end(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;
+ }
+ }
+ }
- if (iv_count) {
- Vector<SpvReflectInterfaceVariable *> input_vars;
- input_vars.resize(iv_count);
+ driver->command_buffer_execute_secondary(frames[frame].draw_command_buffer, VectorView(command_buffers, draw_list_count));
+ memdelete_arr(draw_list);
+ draw_list = nullptr;
- 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.");
+ } else {
+ if (r_last_viewport) {
+ *r_last_viewport = draw_list->viewport;
+ }
+ // Just end the list.
+ memdelete(draw_list);
+ draw_list = nullptr;
+ }
- for (uint32_t j = 0; j < iv_count; j++) {
- if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
- r_reflection_data.vertex_input_mask |= (1ULL << uint32_t(input_vars[j]->location));
- }
+ // Draw_list is no longer active.
+ _THREAD_SAFE_UNLOCK_
+}
+
+void RenderingDevice::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_free();
+
+ driver->command_end_render_pass(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;
+ }
+ }
+ draw_list_bound_textures.clear();
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ BitField<RDD::PipelineStageBits> dst_stages;
+ BitField<RDD::BarrierAccessBits> dst_access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT); // RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT); // RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
+ }
+
+ if (dst_stages.is_empty()) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ }
+
+ RDD::TextureBarrier *texture_barriers = nullptr;
+
+ uint32_t texture_barrier_count = draw_list_storage_textures.size();
+
+ if (texture_barrier_count) {
+ texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * draw_list_storage_textures.size());
+ }
+
+ BitField<RDD::PipelineStageBits> src_stage(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
+ RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+ BitField<RDD::BarrierAccessBits> src_access(
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+
+ if (texture_barrier_count) {
+ src_stage.set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+
+ for (uint32_t i = 0; i < texture_barrier_count; i++) {
+ Texture *texture = texture_owner.get_or_null(draw_list_storage_textures[i]);
+
+ RDD::TextureBarrier &tb = texture_barriers[i];
+ tb.texture = texture->driver_id;
+ tb.src_access = src_access;
+ tb.dst_access = dst_access;
+ tb.prev_layout = texture->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ tb.subresources.aspect = texture->read_aspect_flags;
+ tb.subresources.base_mipmap = texture->base_mipmap;
+ tb.subresources.mipmap_count = texture->mipmaps;
+ tb.subresources.base_layer = texture->base_layer;
+ tb.subresources.layer_count = texture->layers;
+
+ texture->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+
+ // 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).
+
+ RDD::MemoryBarrier mb;
+ mb.src_access = src_access;
+ mb.dst_access = dst_access;
+
+ if (texture_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) {
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stage, dst_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count));
+ }
+ }
+
+ draw_list_storage_textures.clear();
+
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
+#endif
+}
+
+/***********************/
+/**** COMPUTE LISTS ****/
+/***********************/
+
+RenderingDevice::ComputeListID RenderingDevice::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 RenderingDevice::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;
+
+ driver->command_bind_compute_pipeline(cl->command_buffer, pipeline->driver_id);
+
+ if (cl->state.pipeline_shader != pipeline->shader) {
+ // Shader changed, so descriptor sets may become incompatible.
+
+ 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.
+
+ uint32_t first_invalid_set = UINT32_MAX; // All valid by default.
+ switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {
+ case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {
+ first_invalid_set = 0;
+ } break;
+ case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {
+ for (uint32_t i = 0; i < pcount; i++) {
+ if (cl->state.sets[i].pipeline_expected_format != pformats[i]) {
+ first_invalid_set = i;
+ break;
}
}
+ } break;
+ case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {
+ if (cl->state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {
+ first_invalid_set = 0;
+ }
+ } break;
+ }
+
+ for (uint32_t i = 0; i < pcount; i++) {
+ cl->state.sets[i].bound = i >= first_invalid_set;
+ cl->state.sets[i].pipeline_expected_format = pformats[i];
+ }
+
+ 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) {
+#ifdef DEBUG_ENABLED
+ cl->validation.pipeline_push_constant_supplied = false;
+#endif
+ }
+
+ cl->state.pipeline_shader = pipeline->shader;
+ cl->state.pipeline_shader_driver_id = pipeline->shader_driver_id;
+ cl->state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;
+ 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 RenderingDevice::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 >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,
+ "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");
+#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].uniform_set_driver_id = uniform_set->driver_id; // 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;
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ 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();
+
+ RDD::TextureBarrier *texture_barriers = nullptr;
+
+ if (textures_to_sampled_count + textures_to_storage_count) {
+ texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * (textures_to_sampled_count + textures_to_storage_count));
+ }
+ uint32_t texture_barrier_count = 0;
+
+ BitField<RDD::PipelineStageBits> src_stages;
+
+ for (uint32_t i = 0; i < textures_to_sampled_count; i++) {
+ if (textures_to_sampled[i]->layout != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+
+ RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
+ tb.texture = textures_to_sampled[i]->driver_id;
+ tb.src_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ tb.prev_layout = textures_to_sampled[i]->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ tb.subresources.aspect = textures_to_sampled[i]->read_aspect_flags;
+ tb.subresources.base_mipmap = textures_to_sampled[i]->base_mipmap;
+ tb.subresources.mipmap_count = textures_to_sampled[i]->mipmaps;
+ tb.subresources.base_layer = textures_to_sampled[i]->base_layer;
+ tb.subresources.layer_count = textures_to_sampled[i]->layers;
+
+ textures_to_sampled[i]->layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]);
}
- 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 (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;
+ }
- if (ov_count) {
- Vector<SpvReflectInterfaceVariable *> output_vars;
- output_vars.resize(ov_count);
+ Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw();
- 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 i = 0; i < textures_to_storage_count; i++) {
+ if (textures_to_storage[i]->layout != RDD::TEXTURE_LAYOUT_GENERAL) {
+ BitField<RDD::BarrierAccessBits> src_access;
- for (uint32_t j = 0; j < ov_count; j++) {
- const SpvReflectInterfaceVariable *refvar = output_vars[j];
- if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) {
- r_reflection_data.fragment_output_mask |= 1 << refvar->location;
- }
+ if (textures_to_storage[i]->used_in_frame == frames_drawn) {
+ if (textures_to_storage[i]->used_in_compute) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (textures_to_storage[i]->used_in_raster) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
}
+ if (textures_to_storage[i]->used_in_transfer) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_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.clear();
+ 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;
}
+
+ RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
+ tb.texture = textures_to_storage[i]->driver_id;
+ tb.src_access = src_access;
+ tb.dst_access = (RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ tb.prev_layout = textures_to_storage[i]->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_GENERAL;
+ tb.subresources.aspect = textures_to_storage[i]->read_aspect_flags;
+ tb.subresources.base_mipmap = textures_to_storage[i]->base_mipmap;
+ tb.subresources.mipmap_count = textures_to_storage[i]->mipmaps;
+ tb.subresources.base_layer = textures_to_storage[i]->base_layer;
+ tb.subresources.layer_count = textures_to_storage[i]->layers;
+
+ textures_to_storage[i]->layout = RDD::TEXTURE_LAYOUT_GENERAL;
+
+ cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards.
}
+ }
- 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 (texture_barrier_count) {
+ if (src_stages.is_empty()) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+ }
- 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.");
+ driver->command_pipeline_barrier(cl->command_buffer, src_stages, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count));
+ }
+ }
- 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));
- }
+ { // 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 RenderingDevice::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
+ driver->command_bind_push_constants(cl->command_buffer, cl->state.pipeline_shader_driver_id, 0, VectorView((const uint32_t *)p_data, p_data_size / sizeof(uint32_t)));
+#ifdef DEBUG_ENABLED
+ cl->validation.pipeline_push_constant_supplied = true;
+#endif
+}
+
+void RenderingDevice::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);
- ERR_FAIL_COND_V_MSG(r_reflection_data.push_constant_size && r_reflection_data.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.");
+ ComputeList *cl = compute_list;
- r_reflection_data.push_constant_size = pconstants[0]->size;
- r_reflection_data.push_constant_stages_mask.set_flag(stage_flag);
+#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 > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X),
+ "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X)) + ")");
+ ERR_FAIL_COND_MSG(p_y_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y),
+ "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y)) + ")");
+ ERR_FAIL_COND_MSG(p_z_groups > driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z),
+ "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is larger than device limit (" + itos(driver->limit_get(LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z)) + ")");
- //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+ 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
+ driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ }
+ 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.
+ }
+ if (!cl->state.sets[i].bound) {
+ driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ cl->state.sets[i].bound = true;
+ }
+ }
- // Destroy the reflection data when no longer required.
- spvReflectDestroyShaderModule(&module);
+ driver->command_compute_dispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups);
+}
+
+void RenderingDevice::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 RenderingDevice::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_COND(!buffer);
+
+ ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_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
+ driver->command_uniform_set_prepare_for_use(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ }
+ 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.
+ }
+ if (!cl->state.sets[i].bound) {
+ driver->command_bind_compute_uniform_set(cl->command_buffer, cl->state.sets[i].uniform_set_driver_id, cl->state.pipeline_shader_driver_id, i);
+ cl->state.sets[i].bound = true;
}
+ }
+
+ driver->command_compute_dispatch_indirect(cl->command_buffer, buffer->driver_id, p_offset);
+}
+
+void RenderingDevice::compute_list_add_barrier(ComputeListID p_list) {
+ // Must be called within a compute list, the class mutex is locked during that time
+
+ BitField<RDD::PipelineStageBits> stages(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ BitField<RDD::BarrierAccessBits> access(RDD::BARRIER_ACCESS_SHADER_READ_BIT);
+ _compute_list_add_barrier(BARRIER_MASK_COMPUTE, stages, access);
+}
+
+void RenderingDevice::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access) {
+ ERR_FAIL_NULL(compute_list);
+
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::TextureBarrier *texture_barriers = nullptr;
+
+ uint32_t texture_barrier_count = compute_list->state.textures_to_sampled_layout.size();
+
+ if (texture_barrier_count) {
+ texture_barriers = (RDD::TextureBarrier *)alloca(sizeof(RDD::TextureBarrier) * texture_barrier_count);
+ }
+
+ texture_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 != RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ RDD::TextureBarrier &tb = texture_barriers[texture_barrier_count++];
+ tb.texture = E->driver_id;
+ tb.src_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
+ tb.dst_access = p_access;
+ tb.prev_layout = E->layout;
+ tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ tb.subresources.aspect = E->read_aspect_flags;
+ tb.subresources.base_mipmap = E->base_mipmap;
+ tb.subresources.mipmap_count = E->mipmaps;
+ tb.subresources.base_layer = E->base_layer;
+ tb.subresources.layer_count = E->layers;
+
+ E->layout = RDD::TEXTURE_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_stages) {
+ RDD::MemoryBarrier mb;
+ mb.src_access = RDD::BARRIER_ACCESS_SHADER_WRITE_BIT;
+ mb.dst_access = p_access;
+ driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_stages, mb, {}, VectorView(texture_barriers, texture_barrier_count));
- r_reflection_data.stages_mask.set_flag(stage_flag);
+ } else if (texture_barrier_count) {
+ driver->command_pipeline_barrier(compute_list->command_buffer, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count));
+ }
}
- return OK;
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
+#endif
+}
+
+void RenderingDevice::compute_list_end(BitField<BarrierMask> p_post_barrier) {
+ ERR_FAIL_NULL(compute_list);
+
+ BitField<RDD::PipelineStageBits> stages;
+ BitField<RDD::BarrierAccessBits> access;
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
+ stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
+ }
+ _compute_list_add_barrier(p_post_barrier, stages, access);
+
+ memdelete(compute_list);
+ compute_list = nullptr;
+
+ // Compute_list is no longer active.
+ _THREAD_SAFE_UNLOCK_
+}
+
+void RenderingDevice::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
+ if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ return;
+ }
+
+ BitField<RDD::PipelineStageBits> src_stages;
+ BitField<RDD::BarrierAccessBits> src_access;
+
+ if (p_from == 0) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+ } else {
+ if (p_from.has_flag(BARRIER_MASK_COMPUTE)) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT).set_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT).set_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+ }
+ if (p_from.has_flag(BARRIER_MASK_TRANSFER)) {
+ src_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ src_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT);
+ }
+ }
+
+ BitField<RDD::PipelineStageBits> dst_stages;
+ BitField<RDD::BarrierAccessBits> dst_access;
+
+ if (p_to == 0) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+ } else {
+ if (p_to.has_flag(BARRIER_MASK_COMPUTE)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
+ }
+ if (p_to.has_flag(BARRIER_MASK_VERTEX)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT).set_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT).set_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
+ }
+ if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT).set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT).set_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT);
+ }
+ if (p_to.has_flag(BARRIER_MASK_TRANSFER)) {
+ dst_stages.set_flag(RDD::PIPELINE_STAGE_TRANSFER_BIT);
+ dst_access.set_flag(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT).set_flag(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT);
+ }
+ }
+
+ RDD::MemoryBarrier mb;
+ mb.src_access = src_access;
+ mb.dst_access = dst_access;
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, src_stages, dst_stages, mb, {}, {});
+}
+
+void RenderingDevice::full_barrier() {
+#ifndef DEBUG_ENABLED
+ ERR_PRINT("Full barrier is debug-only, should not be used in production");
+#endif
+ _full_barrier(true);
+}
+
+/**************************/
+/**** FRAME MANAGEMENT ****/
+/**************************/
+
+void RenderingDevice::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 RenderingDevice::_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)) {
+ RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);
+ frames[frame].samplers_to_dispose_of.push_back(sampler_driver_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);
+ if (shader->driver_id) { // Not placeholder?
+ 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)) {
+ Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
+ frames[frame].buffers_to_dispose_of.push_back(*texture_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);
+ 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
+ }
+}
+
+// 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 RenderingDevice::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);
+ driver->set_object_name(RDD::OBJECT_TYPE_TEXTURE, texture->driver_id, p_name);
+ } 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)) {
+ RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_SAMPLER, sampler_driver_id, p_name);
+ } else if (vertex_buffer_owner.owns(p_id)) {
+ Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, vertex_buffer->driver_id, p_name);
+ } else if (index_buffer_owner.owns(p_id)) {
+ IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, index_buffer->driver_id, p_name);
+ } else if (shader_owner.owns(p_id)) {
+ Shader *shader = shader_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_SHADER, shader->driver_id, p_name);
+ } else if (uniform_buffer_owner.owns(p_id)) {
+ Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, uniform_buffer->driver_id, p_name);
+ } else if (texture_buffer_owner.owns(p_id)) {
+ Buffer *texture_buffer = texture_buffer_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, texture_buffer->driver_id, p_name);
+ } else if (storage_buffer_owner.owns(p_id)) {
+ Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, storage_buffer->driver_id, p_name);
+ } else if (uniform_set_owner.owns(p_id)) {
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_UNIFORM_SET, uniform_set->driver_id, p_name);
+ } else if (render_pipeline_owner.owns(p_id)) {
+ RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);
+ } else if (compute_pipeline_owner.owns(p_id)) {
+ ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
+ driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, 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 RenderingDevice::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 RenderingDevice::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 RenderingDevice::draw_command_end_label() {
+ _THREAD_SAFE_METHOD_
+ context->command_end_label(frames[frame].draw_command_buffer);
+}
+
+String RenderingDevice::get_device_vendor_name() const {
+ return context->get_device_vendor_name();
+}
+
+String RenderingDevice::get_device_name() const {
+ return context->get_device_name();
+}
+
+RenderingDevice::DeviceType RenderingDevice::get_device_type() const {
+ return context->get_device_type();
+}
+
+String RenderingDevice::get_device_api_version() const {
+ return context->get_device_api_version();
+}
+
+String RenderingDevice::get_device_pipeline_cache_uuid() const {
+ return context->get_device_pipeline_cache_uuid();
+}
+
+void RenderingDevice::_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).");
+ }
+
+ {
+ driver->end_segment();
+ driver->command_buffer_end(frames[frame].setup_command_buffer);
+ driver->command_buffer_end(frames[frame].draw_command_buffer);
+ }
+}
+
+void RenderingDevice::_begin_frame() {
+ // Erase pending resources.
+ _free_pending_resources(frame);
+
+ // Create setup command buffer and set as the setup buffer.
+
+ {
+ bool ok = driver->command_buffer_begin(frames[frame].setup_command_buffer);
+ ERR_FAIL_COND(!ok);
+ ok = driver->command_buffer_begin(frames[frame].draw_command_buffer);
+ ERR_FAIL_COND(!ok);
+
+ 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.
+ }
+
+ driver->begin_segment(frames[frame].draw_command_buffer, frame, frames_drawn);
+ }
+
+ // 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) {
+ driver->timestamp_query_pool_get_results(frames[frame].timestamp_pool, frames[frame].timestamp_count, frames[frame].timestamp_result_values.ptr());
+ driver->command_timestamp_query_pool_reset(frames[frame].setup_command_buffer, frames[frame].timestamp_pool, 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();
+}
+
+void RenderingDevice::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_buffer);
+ _finalize_command_bufers();
+
+ screen_prepared = false;
+ // Swap buffers.
+ context->swap_buffers();
+
+ frame = (frame + 1) % frame_count;
+
+ _begin_frame();
+}
+
+void RenderingDevice::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();
+
+ RDD::CommandBufferID 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 RenderingDevice::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;
+}
+
+void RenderingDevice::_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();
+
+ driver->pipeline_free(pipeline->driver_id);
+
+ 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();
+
+ driver->pipeline_free(pipeline->driver_id);
+
+ 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();
+
+ driver->uniform_set_free(uniform_set->driver_id);
+
+ frames[p_frame].uniform_sets_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();
+
+ driver->shader_free(shader->driver_id);
+
+ frames[p_frame].shaders_to_dispose_of.pop_front();
+ }
+
+ // Samplers.
+ while (frames[p_frame].samplers_to_dispose_of.front()) {
+ RDD::SamplerID sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
+
+ driver->sampler_free(sampler);
+
+ 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.
+ driver->framebuffer_free(E.value.framebuffer);
+ driver->render_pass_free(E.value.render_pass);
+ }
+
+ 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.");
+ }
+
+ texture_memory -= driver->texture_get_allocation_size(texture->driver_id);
+ driver->texture_free(texture->driver_id);
+
+ frames[p_frame].textures_to_dispose_of.pop_front();
+ }
+
+ // Buffers.
+ while (frames[p_frame].buffers_to_dispose_of.front()) {
+ Buffer &buffer = frames[p_frame].buffers_to_dispose_of.front()->get();
+ driver->buffer_free(buffer.driver_id);
+ buffer_memory -= buffer.size;
+
+ frames[p_frame].buffers_to_dispose_of.pop_front();
+ }
+}
+
+void RenderingDevice::prepare_screen_for_drawing() {
+ _THREAD_SAFE_METHOD_
+ context->prepare_buffers(frames[frame].draw_command_buffer);
+ screen_prepared = true;
+}
+
+uint32_t RenderingDevice::get_frame_delay() const {
+ return frame_count;
+}
+
+uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const {
+ switch (p_type) {
+ case MEMORY_BUFFERS: {
+ return buffer_memory;
+ }
+ case MEMORY_TEXTURES: {
+ return texture_memory;
+ }
+ case MEMORY_TOTAL: {
+ return driver->get_total_memory_used();
+ }
+ default: {
+ DEV_ASSERT(false);
+ return 0;
+ }
+ }
+}
+
+void RenderingDevice::_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) {
+ driver->end_segment();
+ driver->command_buffer_end(frames[frame].setup_command_buffer);
+ driver->command_buffer_end(frames[frame].draw_command_buffer);
+ }
+
+ if (local_device.is_valid()) {
+ RDD::CommandBufferID 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);
+
+ bool ok = driver->command_buffer_begin(frames[frame].setup_command_buffer);
+ ERR_FAIL_COND(!ok);
+ ok = driver->command_buffer_begin(frames[frame].draw_command_buffer);
+ ERR_FAIL_COND(!ok);
+
+ driver->begin_segment(frames[frame].draw_command_buffer, frame, frames_drawn);
+ } else {
+ context->flush(p_current_frame, p_current_frame);
+ // Re-create the setup command.
+ if (p_current_frame) {
+ bool ok = driver->command_buffer_begin(frames[frame].setup_command_buffer);
+ ERR_FAIL_COND(!ok);
+
+ context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
+ ok = driver->command_buffer_begin(frames[frame].draw_command_buffer);
+ ERR_FAIL_COND(!ok);
+ context->append_command_buffer(frames[frame].draw_command_buffer);
+
+ driver->begin_segment(frames[frame].draw_command_buffer, frame, frames_drawn);
+ }
+ }
+}
+
+void RenderingDevice::initialize(ApiContextRD *p_context, bool p_local_device) {
+ context = p_context;
+
+ device_capabilities = p_context->get_device_capabilities();
+
+ if (p_local_device) {
+ frame_count = 1;
+ local_device = context->local_device_create();
+ } else {
+ frame_count = 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.
+ }
+ driver = context->get_driver(local_device);
+ max_timestamp_query_elements = 256;
+
+ 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.
+ frames[i].command_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_PRIMARY);
+ ERR_FAIL_COND(!frames[i].command_pool);
+
+ // Create command buffers.
+ frames[i].setup_command_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_PRIMARY, frames[i].command_pool);
+ ERR_CONTINUE(!frames[i].setup_command_buffer);
+ frames[i].draw_command_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_PRIMARY, frames[i].command_pool);
+ ERR_CONTINUE(!frames[i].draw_command_buffer);
+
+ {
+ // Create query pool.
+ frames[i].timestamp_pool = driver->timestamp_query_pool_create(max_timestamp_query_elements);
+ 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.
+ bool ok = driver->command_buffer_begin(frames[0].setup_command_buffer);
+ ERR_FAIL_COND(!ok);
+
+ ok = driver->command_buffer_begin(frames[0].draw_command_buffer);
+ ERR_FAIL_COND(!ok);
+ 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.
+ driver->command_timestamp_query_pool_reset(frames[0].setup_command_buffer, frames[i].timestamp_pool, 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);
+ }
+
+ 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";
+
+ Vector<uint8_t> cache_data = _load_pipeline_cache();
+ pipelines_cache_enabled = driver->pipeline_cache_create(cache_data);
+ if (pipelines_cache_enabled) {
+ pipelines_cache_size = driver->pipeline_cache_query_size();
+ print_verbose(vformat("Startup PSO cache (%.1f MiB)", pipelines_cache_size / (1024.0f * 1024.0f)));
+ }
+}
+
+Vector<uint8_t> RenderingDevice::_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);
+ return file_data;
+ } else {
+ return Vector<uint8_t>();
+ }
+}
+
+void RenderingDevice::_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;
+ }
+ }
+ }
+
+ {
+ size_t new_pipelines_cache_size = driver->pipeline_cache_query_size();
+ ERR_FAIL_COND(!new_pipelines_cache_size);
+ size_t difference = new_pipelines_cache_size - pipelines_cache_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_size = new_pipelines_cache_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 RenderingDevice::_save_pipeline_cache(void *p_data) {
+ RenderingDevice *self = static_cast<RenderingDevice *>(p_data);
+
+ self->_thread_safe_.lock();
+ Vector<uint8_t> cache_blob = self->driver->pipeline_cache_serialize();
+ self->_thread_safe_.unlock();
+
+ if (cache_blob.size() == 0) {
+ return;
+ }
+ print_verbose(vformat("Updated PSO cache (%.1f MiB)", cache_blob.size() / (1024.0f * 1024.0f)));
+
+ Ref<FileAccess> f = FileAccess::open(self->pipelines_cache_file_path, FileAccess::WRITE, nullptr);
+ if (f.is_valid()) {
+ f->store_buffer(cache_blob);
+ }
+}
+
+template <class T>
+void RenderingDevice::_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 RenderingDevice::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.
+ if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ RDD::MemoryBarrier mb;
+ mb.src_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ RDD::BARRIER_ACCESS_INDEX_READ_BIT |
+ RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
+ RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_HOST_READ_BIT |
+ RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
+ mb.dst_access = (RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ RDD::BARRIER_ACCESS_INDEX_READ_BIT |
+ RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ RDD::BARRIER_ACCESS_UNIFORM_READ_BIT |
+ RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_READ_BIT |
+ RDD::BARRIER_ACCESS_SHADER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_READ_BIT |
+ RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT |
+ RDD::BARRIER_ACCESS_HOST_READ_BIT |
+ RDD::BARRIER_ACCESS_HOST_WRITE_BIT);
+
+ driver->command_pipeline_barrier(frames[frame].draw_command_buffer, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, mb, {}, {});
+ }
+
+ driver->command_timestamp_write(frames[frame].draw_command_buffer, 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 RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) {
+ _THREAD_SAFE_METHOD_
+
+ uint64_t driver_id = 0;
+ switch (p_resource) {
+ case DRIVER_RESOURCE_LOGICAL_DEVICE:
+ case DRIVER_RESOURCE_PHYSICAL_DEVICE:
+ case DRIVER_RESOURCE_TOPMOST_OBJECT:
+ case DRIVER_RESOURCE_COMMAND_QUEUE:
+ case DRIVER_RESOURCE_QUEUE_FAMILY:
+ break;
+ case DRIVER_RESOURCE_TEXTURE:
+ case DRIVER_RESOURCE_TEXTURE_VIEW:
+ case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {
+ Texture *tex = texture_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(tex, 0);
+
+ driver_id = tex->driver_id;
+ } break;
+ case DRIVER_RESOURCE_SAMPLER: {
+ RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(sampler_driver_id, 0);
+
+ driver_id = *sampler_driver_id;
+ } break;
+ case DRIVER_RESOURCE_UNIFORM_SET: {
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(uniform_set, 0);
+
+ driver_id = uniform_set->driver_id;
+ } break;
+ case DRIVER_RESOURCE_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);
+ } else if (storage_buffer_owner.owns(p_rid)) {
+ buffer = storage_buffer_owner.get_or_null(p_rid);
+ }
+ ERR_FAIL_NULL_V(buffer, 0);
+
+ driver_id = buffer->driver_id;
+ } break;
+ case DRIVER_RESOURCE_COMPUTE_PIPELINE: {
+ ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(compute_pipeline, 0);
+
+ driver_id = compute_pipeline->driver_id;
+ } break;
+ case DRIVER_RESOURCE_RENDER_PIPELINE: {
+ RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(render_pipeline, 0);
+
+ driver_id = render_pipeline->driver_id;
+ } break;
+ default: {
+ ERR_FAIL_V(0);
+ } break;
+ }
+
+ return driver->get_resource_native_handle(p_resource, driver_id);
+}
+
+uint32_t RenderingDevice::get_captured_timestamps_count() const {
+ return frames[frame].timestamp_result_count;
+}
+
+uint64_t RenderingDevice::get_captured_timestamps_frame() const {
+ return frames[frame].index;
+}
+
+uint64_t RenderingDevice::get_captured_timestamp_gpu_time(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
+ return driver->timestamp_query_result_to_time(frames[frame].timestamp_result_values[p_index]);
+}
+
+uint64_t RenderingDevice::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 RenderingDevice::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 RenderingDevice::limit_get(Limit p_limit) const {
+ return driver->limit_get(p_limit);
+}
+
+void RenderingDevice::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 (uint32_t i = 0; i < frames.size(); i++) {
+ int f = (frame + i) % frames.size();
+ _free_pending_resources(f);
+ driver->command_pool_free(frames[i].command_pool);
+ driver->timestamp_query_pool_free(frames[i].timestamp_pool);
+ }
+
+ if (pipelines_cache_enabled) {
+ _update_pipeline_cache(true);
+ driver->pipeline_cache_free();
+ }
+
+ for (int i = 0; i < split_draw_list_allocators.size(); i++) {
+ driver->command_pool_free(split_draw_list_allocators[i].command_pool);
+ }
+
+ frames.clear();
+
+ for (int i = 0; i < staging_buffer_blocks.size(); i++) {
+ driver->buffer_free(staging_buffer_blocks[i].driver_id);
+ }
+
+ while (vertex_formats.size()) {
+ HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin();
+ driver->vertex_format_free(temp->value.driver_id);
+ vertex_formats.remove(temp);
+ }
+
+ for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) {
+ driver->render_pass_free(E.value.render_pass);
+ }
+ framebuffer_formats.clear();
+
+ // All these should be clear at this point.
+ ERR_FAIL_COND(dependency_map.size());
+ ERR_FAIL_COND(reverse_dependency_map.size());
+}
+
+RenderingDevice *RenderingDevice::create_local_device() {
+ RenderingDevice *rd = memnew(RenderingDevice);
+ rd->initialize(context, true);
+ return rd;
+}
+
+bool RenderingDevice::has_feature(const Features p_feature) const {
+ return driver->has_feature(p_feature);
}
void RenderingDevice::_bind_methods() {
@@ -731,7 +6115,9 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture"), &RenderingDevice::texture_get_native_handle);
+#endif
ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1));
ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1));
@@ -768,7 +6154,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create);
ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid);
- ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update_bind, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0));
@@ -852,6 +6238,20 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(DEVICE_TYPE_CPU);
BIND_ENUM_CONSTANT(DEVICE_TYPE_MAX);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_LOGICAL_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_PHYSICAL_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TOPMOST_OBJECT);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMMAND_QUEUE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_QUEUE_FAMILY);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_VIEW);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_TEXTURE_DATA_FORMAT);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_SAMPLER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_UNIFORM_SET);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_BUFFER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_COMPUTE_PIPELINE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_RENDER_PIPELINE);
+#ifndef DISABLE_DEPRECATED
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE);
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE);
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE);
@@ -865,6 +6265,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER);
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE);
BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE);
+#endif
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8);
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
@@ -1345,8 +6746,326 @@ void RenderingDevice::_bind_methods() {
BIND_CONSTANT(INVALID_FORMAT_ID);
}
+RenderingDevice::~RenderingDevice() {
+ if (local_device.is_valid()) {
+ finalize();
+ context->local_device_free(local_device);
+ }
+ if (singleton == this) {
+ singleton = nullptr;
+ }
+}
+
RenderingDevice::RenderingDevice() {
if (singleton == nullptr) { // there may be more rendering devices later
singleton = this;
}
}
+
+/*****************/
+/**** BINDERS ****/
+/*****************/
+
+RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
+ ERR_FAIL_COND_V(p_format.is_null(), RID());
+ ERR_FAIL_COND_V(p_view.is_null(), RID());
+ Vector<Vector<uint8_t>> data;
+ for (int i = 0; i < p_data.size(); i++) {
+ Vector<uint8_t> byte_slice = p_data[i];
+ ERR_FAIL_COND_V(byte_slice.is_empty(), RID());
+ data.push_back(byte_slice);
+ }
+ return texture_create(p_format->base, p_view->base, data);
+}
+
+RID RenderingDevice::_texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture) {
+ ERR_FAIL_COND_V(p_view.is_null(), RID());
+
+ return texture_create_shared(p_view->base, p_with_texture);
+}
+
+RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) {
+ ERR_FAIL_COND_V(p_view.is_null(), RID());
+
+ return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type);
+}
+
+Ref<RDTextureFormat> RenderingDevice::_texture_get_format(RID p_rd_texture) {
+ Ref<RDTextureFormat> rtf;
+ rtf.instantiate();
+ rtf->base = texture_get_format(p_rd_texture);
+
+ return rtf;
+}
+
+RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {
+ Vector<AttachmentFormat> attachments;
+ attachments.resize(p_attachments.size());
+
+ for (int i = 0; i < p_attachments.size(); i++) {
+ Ref<RDAttachmentFormat> af = p_attachments[i];
+ ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
+ attachments.write[i] = af->base;
+ }
+ return framebuffer_format_create(attachments, p_view_count);
+}
+
+RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) {
+ Vector<AttachmentFormat> attachments;
+ attachments.resize(p_attachments.size());
+
+ for (int i = 0; i < p_attachments.size(); i++) {
+ Ref<RDAttachmentFormat> af = p_attachments[i];
+ ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
+ attachments.write[i] = af->base;
+ }
+
+ Vector<FramebufferPass> passes;
+ for (int i = 0; i < p_passes.size(); i++) {
+ Ref<RDFramebufferPass> pass = p_passes[i];
+ ERR_CONTINUE(pass.is_null());
+ passes.push_back(pass->base);
+ }
+
+ return framebuffer_format_create_multipass(attachments, passes, p_view_count);
+}
+
+RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) {
+ Vector<RID> textures = Variant(p_textures);
+ return framebuffer_create(textures, p_format_check, p_view_count);
+}
+
+RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
+ Vector<RID> textures = Variant(p_textures);
+ Vector<FramebufferPass> passes;
+ for (int i = 0; i < p_passes.size(); i++) {
+ Ref<RDFramebufferPass> pass = p_passes[i];
+ ERR_CONTINUE(pass.is_null());
+ passes.push_back(pass->base);
+ }
+ return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count);
+}
+
+RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) {
+ ERR_FAIL_COND_V(p_state.is_null(), RID());
+
+ return sampler_create(p_state->base);
+}
+
+RenderingDevice::VertexFormatID RenderingDevice::_vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats) {
+ Vector<VertexAttribute> descriptions;
+ descriptions.resize(p_vertex_formats.size());
+
+ for (int i = 0; i < p_vertex_formats.size(); i++) {
+ Ref<RDVertexAttribute> af = p_vertex_formats[i];
+ ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID);
+ descriptions.write[i] = af->base;
+ }
+ return vertex_format_create(descriptions);
+}
+
+RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets) {
+ Vector<RID> buffers = Variant(p_src_buffers);
+
+ Vector<uint64_t> offsets;
+ offsets.resize(p_offsets.size());
+ for (int i = 0; i < p_offsets.size(); i++) {
+ offsets.write[i] = p_offsets[i];
+ }
+
+ return vertex_array_create(p_vertex_count, p_vertex_format, buffers, offsets);
+}
+
+Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) {
+ ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderSPIRV>());
+
+ Ref<RDShaderSPIRV> bytecode;
+ bytecode.instantiate();
+ for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
+ String error;
+
+ ShaderStage stage = ShaderStage(i);
+ String source = p_source->get_stage_source(stage);
+
+ if (!source.is_empty()) {
+ Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, source, p_source->get_language(), &error, p_allow_cache);
+ bytecode->set_stage_bytecode(stage, spirv);
+ bytecode->set_stage_compile_error(stage, error);
+ }
+ }
+ return bytecode;
+}
+
+Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
+ ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());
+
+ Vector<ShaderStageSPIRVData> stage_data;
+ for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
+ ShaderStage stage = ShaderStage(i);
+ ShaderStageSPIRVData sd;
+ sd.shader_stage = stage;
+ String error = p_spirv->get_stage_compile_error(stage);
+ ERR_FAIL_COND_V_MSG(!error.is_empty(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
+ sd.spirv = p_spirv->get_stage_bytecode(stage);
+ if (sd.spirv.is_empty()) {
+ continue;
+ }
+ stage_data.push_back(sd);
+ }
+
+ return shader_compile_binary_from_spirv(stage_data, p_shader_name);
+}
+
+RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
+ ERR_FAIL_COND_V(p_spirv.is_null(), RID());
+
+ Vector<ShaderStageSPIRVData> stage_data;
+ for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
+ ShaderStage stage = ShaderStage(i);
+ ShaderStageSPIRVData sd;
+ sd.shader_stage = stage;
+ String error = p_spirv->get_stage_compile_error(stage);
+ ERR_FAIL_COND_V_MSG(!error.is_empty(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode.");
+ sd.spirv = p_spirv->get_stage_bytecode(stage);
+ if (sd.spirv.is_empty()) {
+ continue;
+ }
+ stage_data.push_back(sd);
+ }
+ return shader_create_from_spirv(stage_data);
+}
+
+RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
+ Vector<Uniform> uniforms;
+ uniforms.resize(p_uniforms.size());
+ for (int i = 0; i < p_uniforms.size(); i++) {
+ Ref<RDUniform> uniform = p_uniforms[i];
+ ERR_FAIL_COND_V(!uniform.is_valid(), RID());
+ uniforms.write[i] = uniform->base;
+ }
+ return uniform_set_create(uniforms, p_shader, p_shader_set);
+}
+
+Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
+ return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
+}
+
+static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
+ Vector<RenderingDevice::PipelineSpecializationConstant> ret;
+ ret.resize(p_constants.size());
+ for (int i = 0; i < p_constants.size(); i++) {
+ Ref<RDPipelineSpecializationConstant> c = p_constants[i];
+ ERR_CONTINUE(c.is_null());
+ RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];
+ Variant value = c->get_value();
+ switch (value.get_type()) {
+ case Variant::BOOL: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.bool_value = value;
+ } break;
+ case Variant::INT: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+ sc.int_value = value;
+ } break;
+ case Variant::FLOAT: {
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
+ sc.float_value = value;
+ } break;
+ default: {
+ }
+ }
+
+ sc.constant_id = c->get_constant_id();
+ }
+ return ret;
+}
+
+RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {
+ PipelineRasterizationState rasterization_state;
+ if (p_rasterization_state.is_valid()) {
+ rasterization_state = p_rasterization_state->base;
+ }
+
+ PipelineMultisampleState multisample_state;
+ if (p_multisample_state.is_valid()) {
+ multisample_state = p_multisample_state->base;
+ for (int i = 0; i < p_multisample_state->sample_masks.size(); i++) {
+ int64_t mask = p_multisample_state->sample_masks[i];
+ multisample_state.sample_mask.push_back(mask);
+ }
+ }
+
+ PipelineDepthStencilState depth_stencil_state;
+ if (p_depth_stencil_state.is_valid()) {
+ depth_stencil_state = p_depth_stencil_state->base;
+ }
+
+ PipelineColorBlendState color_blend_state;
+ if (p_blend_state.is_valid()) {
+ color_blend_state = p_blend_state->base;
+ for (int i = 0; i < p_blend_state->attachments.size(); i++) {
+ Ref<RDPipelineColorBlendStateAttachment> attachment = p_blend_state->attachments[i];
+ if (attachment.is_valid()) {
+ color_blend_state.attachments.push_back(attachment->base);
+ }
+ }
+ }
+
+ return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants));
+}
+
+RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {
+ return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
+}
+
+RenderingDevice::DrawListID RenderingDevice::_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 TypedArray<RID> &p_storage_textures) {
+ Vector<RID> stextures;
+ for (int i = 0; i < p_storage_textures.size(); i++) {
+ stextures.push_back(p_storage_textures[i]);
+ }
+ return draw_list_begin(p_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, stextures);
+}
+
+Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, 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 TypedArray<RID> &p_storage_textures) {
+ Vector<DrawListID> splits;
+ splits.resize(p_splits);
+ Vector<RID> stextures;
+ for (int i = 0; i < p_storage_textures.size(); i++) {
+ stextures.push_back(p_storage_textures[i]);
+ }
+ draw_list_begin_split(p_framebuffer, p_splits, splits.ptrw(), 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, stextures);
+
+ Vector<int64_t> split_ids;
+ split_ids.resize(splits.size());
+ for (int i = 0; i < splits.size(); i++) {
+ split_ids.write[i] = splits[i];
+ }
+
+ return split_ids;
+}
+
+Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) {
+ Vector<DrawListID> splits;
+ splits.resize(p_splits);
+
+ Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw());
+ ERR_FAIL_COND_V(err != OK, Vector<int64_t>());
+
+ Vector<int64_t> split_ids;
+ split_ids.resize(splits.size());
+ for (int i = 0; i < splits.size(); i++) {
+ split_ids.write[i] = splits[i];
+ }
+
+ return split_ids;
+}
+
+void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
+ ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
+ draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
+}
+
+void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
+ ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
+ compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
+}
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index b95640acc6..90ed2828c0 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -32,8 +32,16 @@
#define RENDERING_DEVICE_H
#include "core/object/class_db.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 "core/variant/typed_array.h"
#include "servers/display_server.h"
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_device_commons.h"
+#include "servers/rendering/rendering_device_driver.h"
class RDTextureFormat;
class RDTextureView;
@@ -50,56 +58,16 @@ class RDPipelineColorBlendState;
class RDFramebufferPass;
class RDPipelineSpecializationConstant;
-class RenderingDevice : public Object {
+class RenderingDevice : public RenderingDeviceCommons {
GDCLASS(RenderingDevice, Object)
+
+ _THREAD_SAFE_CLASS_
public:
enum DeviceFamily {
DEVICE_UNKNOWN,
DEVICE_OPENGL,
DEVICE_VULKAN,
- DEVICE_DIRECTX
- };
-
- // 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,
- };
-
- enum DriverResource {
- DRIVER_RESOURCE_VULKAN_DEVICE = 0,
- DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE,
- DRIVER_RESOURCE_VULKAN_INSTANCE,
- DRIVER_RESOURCE_VULKAN_QUEUE,
- DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX,
- DRIVER_RESOURCE_VULKAN_IMAGE,
- DRIVER_RESOURCE_VULKAN_IMAGE_VIEW,
- DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT,
- DRIVER_RESOURCE_VULKAN_SAMPLER,
- DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET,
- DRIVER_RESOURCE_VULKAN_BUFFER,
- DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE,
- DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE,
- //next driver continue enum from 1000 to keep order
- };
-
- 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),
+ DEVICE_DIRECTX,
};
enum ShaderLanguage {
@@ -121,8 +89,8 @@ public:
struct Capabilities {
// main device info
DeviceFamily device_family = DEVICE_UNKNOWN;
- uint32_t version_major = 1.0;
- uint32_t version_minor = 0.0;
+ uint32_t version_major = 1;
+ uint32_t version_minor = 0;
};
typedef String (*ShaderSPIRVGetCacheKeyFunction)(const RenderingDevice *p_render_device);
@@ -138,6 +106,10 @@ private:
static RenderingDevice *singleton;
+ Capabilities device_capabilities;
+
+ RenderingDeviceDriver *driver = nullptr; // Owned by the context.
+
protected:
static void _bind_methods();
@@ -146,257 +118,38 @@ protected:
static void _bind_compatibility_methods();
#endif
- Capabilities device_capabilities;
-
+ /***************************/
+ /**** ID INFRASTRUCTURE ****/
+ /***************************/
public:
//base numeric ID for all types
enum {
- INVALID_ID = -1,
INVALID_FORMAT_ID = -1
};
- /*****************/
- /**** GENERIC ****/
- /*****************/
-
- 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 //not an actual operator, just the amount of operators :D
+ 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.
+ ID_MASK = (ID_BASE_SHIFT - 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
- };
+private:
+ 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);
/*****************/
/**** BARRIER ****/
/*****************/
+public:
enum BarrierMask {
BARRIER_MASK_VERTEX = 1,
BARRIER_MASK_FRAGMENT = 8,
@@ -408,172 +161,198 @@ public:
BARRIER_MASK_NO_BARRIER = 0x8000,
};
- /*****************/
- /**** 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
+private:
+ void _full_barrier(bool p_sync_with_draw);
+
+ /***************************/
+ /**** 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 {
+ RDD::BufferID driver_id;
+ uint64_t frame_used = 0;
+ uint32_t fill_amount = 0;
};
- 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
- };
+ 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;
- 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),
- };
+ 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();
- 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
+ struct Buffer {
+ RDD::BufferID driver_id;
+ uint32_t size = 0;
+ BitField<RDD::BufferUsageBits> usage;
};
- struct TextureFormat {
- DataFormat format;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- uint32_t array_layers;
- uint32_t mipmaps;
- TextureType texture_type;
- TextureSamples samples;
- uint32_t usage_bits;
- Vector<DataFormat> shareable_formats;
- bool is_resolve_buffer = false;
+ Buffer *_get_buffer_from_owner(RID p_buffer, BitField<RDD::PipelineStageBits> &r_stages, BitField<RDD::BarrierAccessBits> &r_access, BitField<BarrierMask> p_post_barrier);
+ 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);
- 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;
- }
- }
+ RID_Owner<Buffer> uniform_buffer_owner;
+ RID_Owner<Buffer> storage_buffer_owner;
+ RID_Owner<Buffer> texture_buffer_owner;
- TextureFormat() {
- format = DATA_FORMAT_R8_UNORM;
- width = 1;
- height = 1;
- depth = 1;
- array_layers = 1;
- mipmaps = 1;
- texture_type = TEXTURE_TYPE_2D;
- samples = TEXTURE_SAMPLES_1;
- usage_bits = 0;
- }
+public:
+ 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);
+ 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);
+ Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0); // This causes stall, only use to retrieve large buffers for saving.
+
+ /*****************/
+ /**** TEXTURE ****/
+ /*****************/
+
+ // In modern APIs, the concept of textures may 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 {
+ RDD::TextureID driver_id;
+
+ TextureType type = TEXTURE_TYPE_MAX;
+ DataFormat format = DATA_FORMAT_MAX;
+ TextureSamples samples = TEXTURE_SAMPLES_MAX;
+ 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;
+
+ RDD::TextureLayout layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
+
+ 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;
+
+ BitField<RDD::TextureAspectBits> read_aspect_flags;
+ BitField<RDD::TextureAspectBits> barrier_aspect_flags;
+ 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(Texture *tex, 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);
+
+public:
struct TextureView {
- DataFormat format_override;
- TextureSwizzle swizzle_r;
- TextureSwizzle swizzle_g;
- TextureSwizzle swizzle_b;
- TextureSwizzle swizzle_a;
-
- bool operator==(const TextureView &p_view) const {
- if (format_override != p_view.format_override) {
+ DataFormat format_override = DATA_FORMAT_MAX; // // Means, use same as format.
+ TextureSwizzle swizzle_r = TEXTURE_SWIZZLE_R;
+ TextureSwizzle swizzle_g = TEXTURE_SWIZZLE_G;
+ TextureSwizzle swizzle_b = TEXTURE_SWIZZLE_B;
+ TextureSwizzle swizzle_a = TEXTURE_SWIZZLE_A;
+
+ bool operator==(const TextureView &p_other) const {
+ if (format_override != p_other.format_override) {
return false;
- } else if (swizzle_r != p_view.swizzle_r) {
+ } else if (swizzle_r != p_other.swizzle_r) {
return false;
- } else if (swizzle_g != p_view.swizzle_g) {
+ } else if (swizzle_g != p_other.swizzle_g) {
return false;
- } else if (swizzle_b != p_view.swizzle_b) {
+ } else if (swizzle_b != p_other.swizzle_b) {
return false;
- } else if (swizzle_a != p_view.swizzle_a) {
+ } else if (swizzle_a != p_other.swizzle_a) {
return false;
} else {
return true;
}
}
-
- TextureView() {
- format_override = DATA_FORMAT_MAX; //means, use same as format
- swizzle_r = TEXTURE_SWIZZLE_R;
- swizzle_g = TEXTURE_SWIZZLE_G;
- swizzle_b = TEXTURE_SWIZZLE_B;
- swizzle_a = TEXTURE_SWIZZLE_A;
- }
};
- virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>()) = 0;
- virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0;
- 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) = 0;
-
- enum TextureSliceType {
- TEXTURE_SLICE_2D,
- TEXTURE_SLICE_CUBEMAP,
- TEXTURE_SLICE_3D,
- TEXTURE_SLICE_2D_ARRAY,
- };
+ RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
+ RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
+ RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, BitField<RenderingDevice::TextureUsageBits> p_usage, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
+ 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);
+ 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);
+ Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush
+
+ bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<TextureUsageBits> p_usage) const;
+ bool texture_is_shared(RID p_texture);
+ bool texture_is_valid(RID p_texture);
+ TextureFormat texture_get_format(RID p_texture);
+ Size2i texture_size(RID p_texture);
+#ifndef DISABLE_DEPRECATED
+ uint64_t texture_get_native_handle(RID p_texture);
+#endif
- 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) = 0;
+ 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);
+ 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);
+ Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- 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) = 0;
- virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush
+ /************************/
+ /**** DRAW LISTS (I) ****/
+ /************************/
- virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const = 0;
- virtual bool texture_is_shared(RID p_texture) = 0;
- virtual bool texture_is_valid(RID p_texture) = 0;
- virtual TextureFormat texture_get_format(RID p_texture) = 0;
- virtual Size2i texture_size(RID p_texture) = 0;
- virtual uint64_t texture_get_native_handle(RID p_texture) = 0;
+ enum InitialAction {
+ INITIAL_ACTION_CLEAR, // Start rendering and clear the whole framebuffer.
+ INITIAL_ACTION_CLEAR_REGION, // Start rendering and clear the framebuffer in the specified region.
+ INITIAL_ACTION_CLEAR_REGION_CONTINUE, // Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
+ INITIAL_ACTION_KEEP, // Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition.
+ INITIAL_ACTION_DROP, // Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color.
+ INITIAL_ACTION_CONTINUE, // Continue rendering. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
+ INITIAL_ACTION_MAX
+ };
- 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) = 0;
- 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) = 0;
- virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
+ enum FinalAction {
+ FINAL_ACTION_READ, // Store the texture for reading and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
+ FINAL_ACTION_DISCARD, // Discard the texture data and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
+ FINAL_ACTION_CONTINUE, // Store the texture and continue for further processing. Similar to `FINAL_ACTION_READ`, but does not make the texture read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit.
+ FINAL_ACTION_MAX
+ };
/*********************/
/**** FRAMEBUFFER ****/
/*********************/
+ // In modern APIs, generally, framebuffers work similar to how they
+ // do in OpenGL, with the exception that
+ // the "format" (RDD::RenderPassID) is not dynamic
+ // and must be more or less the same as the one
+ // used for the render pipelines.
+
struct AttachmentFormat {
enum { UNUSED_ATTACHMENT = 0xFFFFFFFF };
DataFormat format;
@@ -586,14 +365,7 @@ public:
}
};
- typedef int64_t FramebufferFormatID;
-
- // This ID is warranted to be unique for the same formats, does not need to be freed
- virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1) = 0;
struct FramebufferPass {
- enum {
- ATTACHMENT_UNUSED = -1
- };
Vector<int32_t> color_attachments;
Vector<int32_t> input_attachments;
Vector<int32_t> resolve_attachments;
@@ -602,193 +374,446 @@ public:
int32_t vrs_attachment = ATTACHMENT_UNUSED; // density map for VRS, only used if supported
};
- virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0;
- virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0;
- virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0) = 0;
+ typedef int64_t FramebufferFormatID;
- virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
- 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) = 0;
- virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0;
- virtual bool framebuffer_is_valid(RID p_framebuffer) const = 0;
- virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) = 0;
+private:
+ 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;
+ }
- virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
+ 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;
+ }
+ }
- /*****************/
- /**** SAMPLER ****/
- /*****************/
+ int as = attachments.size();
+ int bs = p_key.attachments.size();
+ if (as != bs) {
+ return as < bs;
+ }
- enum SamplerFilter {
- SAMPLER_FILTER_NEAREST,
- SAMPLER_FILTER_LINEAR,
- };
+ 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;
+ }
+ }
- 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
+ return false; // Equal.
+ }
};
- 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
+ RDD::RenderPassID _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;
+ RDD::RenderPassID render_pass; // 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.
};
- struct SamplerState {
- SamplerFilter mag_filter;
- SamplerFilter min_filter;
- SamplerFilter mip_filter;
- SamplerRepeatMode repeat_u;
- SamplerRepeatMode repeat_v;
- SamplerRepeatMode repeat_w;
- float lod_bias;
- bool use_anisotropy;
- float anisotropy_max;
- bool enable_compare;
- CompareOperator compare_op;
- float min_lod;
- float max_lod;
- SamplerBorderColor border_color;
- bool unnormalized_uvw;
-
- SamplerState() {
- mag_filter = SAMPLER_FILTER_NEAREST;
- min_filter = SAMPLER_FILTER_NEAREST;
- mip_filter = SAMPLER_FILTER_NEAREST;
- repeat_u = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- repeat_v = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- repeat_w = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- lod_bias = 0;
- use_anisotropy = false;
- anisotropy_max = 1.0;
- enable_compare = false;
- compare_op = COMPARE_OP_ALWAYS;
- min_lod = 0;
- max_lod = 1e20; //something very large should do
- border_color = SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
- unnormalized_uvw = false;
- }
+ HashMap<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
+
+ struct Framebuffer {
+ FramebufferFormatID format_id;
+ 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 {
+ RDD::FramebufferID framebuffer;
+ RDD::RenderPassID render_pass; // This one is owned.
+ uint32_t subpass_count = 1;
+ };
+
+ RBMap<VersionKey, Version> framebuffers;
+ Size2 size;
+ uint32_t view_count;
};
- virtual RID sampler_create(const SamplerState &p_state) = 0;
- virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const = 0;
+ RID_Owner<Framebuffer> framebuffer_owner;
+
+public:
+ // This ID is warranted to be unique for the same formats, does not need to be freed
+ FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
+ FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
+ FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
+ TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
+
+ RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
+ 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);
+ RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
+ bool framebuffer_is_valid(RID p_framebuffer) const;
+ void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata);
+
+ FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
+
+ /*****************/
+ /**** SAMPLER ****/
+ /*****************/
+private:
+ RID_Owner<RDD::SamplerID> sampler_owner;
+
+public:
+ RID sampler_create(const SamplerState &p_state);
+ bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const;
/**********************/
/**** VERTEX ARRAY ****/
/**********************/
- enum VertexFrequency {
- VERTEX_FREQUENCY_VERTEX,
- VERTEX_FREQUENCY_INSTANCE,
+ typedef int64_t VertexFormatID;
+
+private:
+ // 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 VertexAttribute {
- uint32_t location; //shader location
- uint32_t offset;
- DataFormat format;
- uint32_t stride;
- VertexFrequency frequency;
- VertexAttribute() {
- location = 0;
- offset = 0;
- stride = 0;
- format = DATA_FORMAT_MAX;
- frequency = VERTEX_FREQUENCY_VERTEX;
+ struct VertexDescriptionHash {
+ static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) {
+ return p_key.hash();
}
};
- 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) = 0;
- typedef int64_t VertexFormatID;
+ // 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;
- // This ID is warranted to be unique for the same formats, does not need to be freed
- virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) = 0;
- 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>()) = 0;
+ struct VertexDescriptionCache {
+ Vector<VertexAttribute> vertex_formats;
+ RDD::VertexFormatID driver_id;
+ };
- enum IndexBufferFormat {
- INDEX_BUFFER_FORMAT_UINT16,
- INDEX_BUFFER_FORMAT_UINT32,
+ HashMap<VertexFormatID, VertexDescriptionCache> vertex_formats;
+
+ struct VertexArray {
+ RID buffer;
+ VertexFormatID description;
+ int vertex_count = 0;
+ uint32_t max_instances_allowed = 0;
+
+ Vector<RDD::BufferID> buffers; // Not owned, just referenced.
+ Vector<uint64_t> offsets;
};
- 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) = 0;
- virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) = 0;
+ RID_Owner<VertexArray> vertex_array_owner;
+
+ struct IndexBuffer : public Buffer {
+ uint32_t max_index = 0; // Used for validation.
+ uint32_t index_count = 0;
+ IndexBufferFormat format = INDEX_BUFFER_FORMAT_UINT16;
+ 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.
+ RDD::BufferID driver_id; // Not owned, inherited from index buffer.
+ uint32_t offset = 0;
+ uint32_t indices = 0;
+ IndexBufferFormat format = INDEX_BUFFER_FORMAT_UINT16;
+ bool supports_restart_indices = false;
+ };
+
+ RID_Owner<IndexArray> index_array_owner;
+
+public:
+ RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
+
+ // This ID is warranted to be unique for the same formats, does not need to be freed
+ VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_descriptions);
+ 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>());
+
+ 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);
+ RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count);
/****************/
/**** SHADER ****/
/****************/
- const Capabilities *get_device_capabilities() const { return &device_capabilities; };
+ // Some APIs (e.g., 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.
- 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,
+private:
+ struct UniformSetFormat {
+ Vector<ShaderUniform> uniforms;
+
+ _FORCE_INLINE_ bool operator<(const UniformSetFormat &p_other) const {
+ if (uniforms.size() != p_other.uniforms.size()) {
+ return uniforms.size() < p_other.uniforms.size();
+ }
+ for (int i = 0; i < uniforms.size(); i++) {
+ if (uniforms[i] < p_other.uniforms[i]) {
+ return true;
+ } else if (p_other.uniforms[i] < uniforms[i]) {
+ return false;
+ }
+ }
+ 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 : public ShaderDescription {
+ String name; // Used for debug.
+ RDD::ShaderID driver_id;
+ uint32_t layout_hash = 0;
+ Vector<uint32_t> set_formats;
};
- virtual bool has_feature(const Features p_feature) const = 0;
- virtual Vector<uint8_t> shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
- virtual String shader_get_spirv_cache_key() const;
+ String _shader_uniform_debug(RID p_shader, int p_set = -1);
+
+ RID_Owner<Shader> shader_owner;
+
+#ifndef DISABLE_DEPRECATED
+ BitField<BarrierMask> _convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier);
+ void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
+ void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
+ void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to);
+#endif
+
+public:
+ ApiContextRD *get_context() const { return context; }
+
+ const Capabilities *get_device_capabilities() const { return &device_capabilities; };
+
+ bool has_feature(const Features p_feature) const;
+
+ Vector<uint8_t> shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
+ String shader_get_spirv_cache_key() const;
static void shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function);
static void shader_set_spirv_cache_function(ShaderCacheFunction p_function);
static void shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function);
- struct ShaderStageSPIRVData {
- ShaderStage shader_stage;
- Vector<uint8_t> spir_v;
+ String shader_get_binary_cache_key() const;
+ Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
- ShaderStageSPIRVData() {
- shader_stage = SHADER_STAGE_VERTEX;
- }
- };
-
- virtual String shader_get_binary_cache_key() const = 0;
- virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "") = 0;
+ RID shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
+ RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder = RID());
+ RID shader_create_placeholder();
- virtual RID shader_create_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()) = 0;
- virtual RID shader_create_placeholder() = 0;
-
- virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
+ uint64_t shader_get_vertex_input_attribute_mask(RID p_shader);
/******************/
/**** UNIFORMS ****/
/******************/
- 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
- };
-
enum StorageBufferUsage {
STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1,
};
- virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
- virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0) = 0;
- virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+ RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
+ RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0);
+ RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>());
struct Uniform {
- UniformType uniform_type;
- int binding; // Binding index as specified in shader.
+ UniformType uniform_type = UNIFORM_TYPE_IMAGE;
+ uint32_t binding = 0; // Binding index as specified in shader.
private:
// In most cases only one ID is provided per binding, so avoid allocating memory unnecessarily for performance.
@@ -846,465 +871,432 @@ public:
binding = p_binding;
ids = p_ids;
}
- _FORCE_INLINE_ Uniform() {
- uniform_type = UNIFORM_TYPE_IMAGE;
- binding = 0;
- }
+ _FORCE_INLINE_ Uniform() = default;
};
- virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
- virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
- virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) = 0;
+private:
+ // 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;
+ RDD::UniformSetID driver_id;
+ struct AttachableTexture {
+ uint32_t bind = 0;
+ RID texture;
+ };
- 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) = 0;
- 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) = 0;
- virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
- virtual Vector<uint8_t> buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0) = 0; // This causes stall, only use to retrieve large buffers for saving.
+ 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;
+ };
- /******************************************/
- /**** PIPELINE SPECIALIZATION CONSTANT ****/
- /******************************************/
+ RID_Owner<UniformSet> uniform_set_owner;
- enum PipelineSpecializationConstantType {
- PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL,
- PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT,
- PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT,
+public:
+ RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
+ bool uniform_set_is_valid(RID p_uniform_set);
+ void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
+
+ /*******************/
+ /**** 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.
+private:
+ struct RenderPipeline {
+ // Cached values for validation.
+#ifdef DEBUG_ENABLED
+ struct Validation {
+ FramebufferFormatID framebuffer_format;
+ uint32_t render_pass = 0;
+ uint32_t dynamic_state = 0;
+ VertexFormatID vertex_format;
+ bool uses_restart_indices = false;
+ uint32_t primitive_minimum = 0;
+ uint32_t primitive_divisor = 0;
+ } validation;
+#endif
+ // Actual pipeline.
+ RID shader;
+ RDD::ShaderID shader_driver_id;
+ uint32_t shader_layout_hash = 0;
+ Vector<uint32_t> set_formats;
+ RDD::PipelineID driver_id;
+ uint32_t push_constant_size = 0;
};
- struct PipelineSpecializationConstant {
- PipelineSpecializationConstantType type;
- uint32_t constant_id;
- union {
- uint32_t int_value;
- float float_value;
- bool bool_value;
- };
-
- PipelineSpecializationConstant() {
- type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- constant_id = 0;
- int_value = 0;
- }
+ RID_Owner<RenderPipeline> render_pipeline_owner;
+
+ bool pipelines_cache_enabled = false;
+ size_t pipelines_cache_size = 0;
+ String pipelines_cache_file_path;
+ WorkerThreadPool::TaskID pipelines_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;
+
+ Vector<uint8_t> _load_pipeline_cache();
+ void _update_pipeline_cache(bool p_closing = false);
+ static void _save_pipeline_cache(void *p_data);
+
+ struct ComputePipeline {
+ RID shader;
+ RDD::ShaderID shader_driver_id;
+ uint32_t shader_layout_hash = 0;
+ Vector<uint32_t> set_formats;
+ RDD::PipelineID driver_id;
+ uint32_t push_constant_size = 0;
+ uint32_t local_group_size[3] = { 0, 0, 0 };
};
+ RID_Owner<ComputePipeline> compute_pipeline_owner;
+
+public:
+ 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>());
+ bool render_pipeline_is_valid(RID p_pipeline);
+
+ RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
+ bool compute_pipeline_is_valid(RID p_pipeline);
+
+ /****************/
+ /**** SCREEN ****/
+ /****************/
+
+ int screen_get_width(DisplayServer::WindowID p_screen = 0) const;
+ int screen_get_height(DisplayServer::WindowID p_screen = 0) const;
+ FramebufferFormatID screen_get_framebuffer_format() const;
+
/*************************/
- /**** RENDER PIPELINE ****/
+ /**** DRAW LISTS (II) ****/
/*************************/
- 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
+ typedef int64_t DrawListID;
+
+private:
+ // 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 {
+ RDD::CommandPoolID command_pool;
+ Vector<RDD::CommandBufferID> command_buffers; // One for each frame.
};
- //disable optimization, tessellate control points
+ Vector<SplitDrawListAllocator> split_draw_list_allocators;
- enum PolygonCullMode {
- POLYGON_CULL_DISABLED,
- POLYGON_CULL_FRONT,
- POLYGON_CULL_BACK,
- };
+ struct DrawList {
+ RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
+ Rect2i viewport;
+ bool viewport_set = false;
- enum PolygonFrontFace {
- POLYGON_FRONT_FACE_CLOCKWISE,
- POLYGON_FRONT_FACE_COUNTER_CLOCKWISE,
- };
+ struct SetState {
+ uint32_t pipeline_expected_format = 0;
+ uint32_t uniform_set_format = 0;
+ RDD::UniformSetID uniform_set_driver_id;
+ RID uniform_set;
+ bool bound = false;
+ };
- 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 //not an actual operator, just the amount of operators :D
+ struct State {
+ SetState sets[MAX_UNIFORM_SETS];
+ uint32_t set_count = 0;
+ RID pipeline;
+ RID pipeline_shader;
+ RDD::ShaderID pipeline_shader_driver_id;
+ uint32_t pipeline_shader_layout_hash = 0;
+ RID vertex_array;
+ RID index_array;
+ } 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
};
- 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 //not an actual operator, just the amount of operators :D
- };
+ 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;
+ RDD::RenderPassID draw_list_render_pass;
+ RDD::FramebufferID draw_list_vkframebuffer;
+#ifdef DEBUG_ENABLED
+ FramebufferFormatID draw_list_framebuffer_format = INVALID_ID;
+#endif
+ uint32_t draw_list_current_subpass = 0;
- 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
- };
+ 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;
- 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 //not an actual operator, just the amount of operators :D
- };
+ 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, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count);
+ Error _draw_list_render_pass_begin(Framebuffer *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_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, RDD::CommandBufferID p_command_buffer, RDD::CommandBufferType p_cmd_buffer_mode, const Vector<RID> &p_storage_textures, bool p_constrained_to_region);
+ _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
+ 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);
- struct PipelineRasterizationState {
- bool enable_depth_clamp;
- bool discard_primitives;
- bool wireframe;
- PolygonCullMode cull_mode;
- PolygonFrontFace front_face;
- bool depth_bias_enabled;
- float depth_bias_constant_factor;
- float depth_bias_clamp;
- float depth_bias_slope_factor;
- float line_width;
- uint32_t patch_control_points;
- PipelineRasterizationState() {
- enable_depth_clamp = false;
- discard_primitives = false;
- wireframe = false;
- cull_mode = POLYGON_CULL_DISABLED;
- front_face = POLYGON_FRONT_FACE_CLOCKWISE;
- depth_bias_enabled = false;
- depth_bias_constant_factor = 0;
- depth_bias_clamp = 0;
- depth_bias_slope_factor = 0;
- line_width = 1.0;
- patch_control_points = 1;
- }
- };
+public:
+ DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
+ 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>());
+ 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>());
- struct PipelineMultisampleState {
- TextureSamples sample_count;
- bool enable_sample_shading;
- float min_sample_shading;
- Vector<uint32_t> sample_mask;
- bool enable_alpha_to_coverage;
- bool enable_alpha_to_one;
-
- PipelineMultisampleState() {
- sample_count = TEXTURE_SAMPLES_1;
- enable_sample_shading = false;
- min_sample_shading = 0;
- enable_alpha_to_coverage = false;
- enable_alpha_to_one = false;
- }
- };
+ void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
+ void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
+ void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
+ void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array);
+ void draw_list_bind_index_array(DrawListID p_list, RID p_index_array);
+ void draw_list_set_line_width(DrawListID p_list, float p_width);
+ void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size);
- struct PipelineDepthStencilState {
- bool enable_depth_test;
- bool enable_depth_write;
- CompareOperator depth_compare_operator;
- bool enable_depth_range;
- float depth_range_min;
- float depth_range_max;
- bool enable_stencil;
-
- struct StencilOperationState {
- StencilOperation fail;
- StencilOperation pass;
- StencilOperation depth_fail;
- CompareOperator compare;
- uint32_t compare_mask;
- uint32_t write_mask;
- uint32_t reference;
-
- StencilOperationState() {
- fail = STENCIL_OP_ZERO;
- pass = STENCIL_OP_ZERO;
- depth_fail = STENCIL_OP_ZERO;
- compare = COMPARE_OP_ALWAYS;
- compare_mask = 0;
- write_mask = 0;
- reference = 0;
- }
- };
+ void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
- StencilOperationState front_op;
- StencilOperationState back_op;
-
- PipelineDepthStencilState() {
- enable_depth_test = false;
- enable_depth_write = false;
- depth_compare_operator = COMPARE_OP_ALWAYS;
- enable_depth_range = false;
- depth_range_min = 0;
- depth_range_max = 0;
- enable_stencil = false;
- }
- };
+ void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
+ void draw_list_disable_scissor(DrawListID p_list);
- struct PipelineColorBlendState {
- bool enable_logic_op;
- LogicOperation logic_op;
- struct Attachment {
- bool enable_blend;
- BlendFactor src_color_blend_factor;
- BlendFactor dst_color_blend_factor;
- BlendOperation color_blend_op;
- BlendFactor src_alpha_blend_factor;
- BlendFactor dst_alpha_blend_factor;
- BlendOperation alpha_blend_op;
- bool write_r;
- bool write_g;
- bool write_b;
- bool write_a;
- Attachment() {
- enable_blend = false;
- src_color_blend_factor = BLEND_FACTOR_ZERO;
- dst_color_blend_factor = BLEND_FACTOR_ZERO;
- color_blend_op = BLEND_OP_ADD;
- src_alpha_blend_factor = BLEND_FACTOR_ZERO;
- dst_alpha_blend_factor = BLEND_FACTOR_ZERO;
- alpha_blend_op = BLEND_OP_ADD;
- write_r = true;
- write_g = true;
- write_b = true;
- write_a = true;
- }
- };
+ uint32_t draw_list_get_current_pass();
+ DrawListID draw_list_switch_to_next_pass();
+ Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
- 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;
- }
+ void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- 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;
- }
+ /***********************/
+ /**** COMPUTE LISTS ****/
+ /***********************/
- Vector<Attachment> attachments; //one per render target texture
- Color blend_constant;
+ typedef int64_t ComputeListID;
- PipelineColorBlendState() {
- enable_logic_op = false;
- logic_op = LOGIC_OP_CLEAR;
- }
- };
+private:
+ struct ComputeList {
+ RDD::CommandBufferID command_buffer; // 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;
+ RDD::UniformSetID uniform_set_driver_id;
+ RID uniform_set;
+ bool bound = false;
+ };
- 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),
+ struct State {
+ HashSet<Texture *> textures_to_sampled_layout;
+ SetState sets[MAX_UNIFORM_SETS];
+ uint32_t set_count = 0;
+ RID pipeline;
+ RID pipeline_shader;
+ RDD::ShaderID pipeline_shader_driver_id;
+ uint32_t pipeline_shader_layout_hash = 0;
+ uint32_t local_group_size[3] = { 0, 0, 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
};
- virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
- 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>()) = 0;
+ ComputeList *compute_list = nullptr;
- /**************************/
- /**** COMPUTE PIPELINE ****/
- /**************************/
+ void _compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, BitField<RDD::PipelineStageBits> p_stages, BitField<RDD::BarrierAccessBits> p_access);
- virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0;
- virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
+public:
+ ComputeListID compute_list_begin(bool p_allow_draw_overlap = false);
+ void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline);
+ void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index);
+ void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size);
+ void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
+ void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads);
+ void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset);
+ void compute_list_add_barrier(ComputeListID p_list);
- /****************/
- /**** SCREEN ****/
- /****************/
+ void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- virtual int screen_get_width(DisplayServer::WindowID p_screen = 0) const = 0;
- virtual int screen_get_height(DisplayServer::WindowID p_screen = 0) const = 0;
- virtual FramebufferFormatID screen_get_framebuffer_format() const = 0;
+ void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
+ void full_barrier();
- /********************/
- /**** DRAW LISTS ****/
- /********************/
+ /**************************/
+ /**** FRAME MANAGEMENT ****/
+ /**************************/
- enum InitialAction {
- INITIAL_ACTION_CLEAR, // Start rendering and clear the whole framebuffer.
- INITIAL_ACTION_CLEAR_REGION, // Start rendering and clear the framebuffer in the specified region.
- INITIAL_ACTION_CLEAR_REGION_CONTINUE, // Continue rendering and clear the framebuffer in the specified region. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
- INITIAL_ACTION_KEEP, // Start rendering, but keep attached color texture contents. If the framebuffer was previously used to read in a shader, this will automatically insert a layout transition.
- INITIAL_ACTION_DROP, // Start rendering, ignore what is there; write above it. In general, this is the fastest option when you will be writing every single pixel and you don't need a clear color.
- INITIAL_ACTION_CONTINUE, // Continue rendering. Framebuffer must have been left in `FINAL_ACTION_CONTINUE` state as the final action previously.
- INITIAL_ACTION_MAX
- };
+ // 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.
- enum FinalAction {
- FINAL_ACTION_READ, // Store the texture for reading and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
- FINAL_ACTION_DISCARD, // Discard the texture data and make it read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit (only applies to color, depth and stencil attachments).
- FINAL_ACTION_CONTINUE, // Store the texture and continue for further processing. Similar to `FINAL_ACTION_READ`, but does not make the texture read-only if it has the `TEXTURE_USAGE_SAMPLING_BIT` bit.
- FINAL_ACTION_MAX
- };
+private:
+ 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<RDD::SamplerID> samplers_to_dispose_of;
+ List<Shader> shaders_to_dispose_of;
+ List<UniformSet> uniform_sets_to_dispose_of;
+ List<RenderPipeline> render_pipelines_to_dispose_of;
+ List<ComputePipeline> compute_pipelines_to_dispose_of;
+
+ RDD::CommandPoolID command_pool;
+ // 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.
+ RDD::CommandBufferID setup_command_buffer; // Used at the beginning of every frame for set-up.
+ // The main cmd buffer for drawing and compute.
+ // Primarily intended to be used by the main thread to do most stuff.
+ RDD::CommandBufferID draw_command_buffer; // Used at the beginning of every frame for set-up.
+
+ struct Timestamp {
+ String description;
+ uint64_t value = 0;
+ };
- typedef int64_t DrawListID;
+ RDD::QueryPoolID timestamp_pool;
- virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()) = 0;
- 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>()) = 0;
- 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>()) = 0;
+ 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;
+ };
- virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) = 0;
- virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
- virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
- virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0;
- virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0;
- virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
- virtual void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) = 0;
+ uint32_t max_timestamp_query_elements = 0;
- virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 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;
- virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
- virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
+ void _free_pending_resources(int p_frame);
- virtual uint32_t draw_list_get_current_pass() = 0;
- virtual DrawListID draw_list_switch_to_next_pass() = 0;
- virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0;
+ ApiContextRD *context = nullptr;
- virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
+ uint64_t texture_memory = 0;
+ uint64_t buffer_memory = 0;
- /***********************/
- /**** COMPUTE LISTS ****/
- /***********************/
+ void _free_internal(RID p_id);
+ void _flush(bool p_current_frame);
- typedef int64_t ComputeListID;
+ bool screen_prepared = false;
- virtual ComputeListID compute_list_begin(bool p_allow_draw_overlap = false) = 0;
- virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0;
- virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
- virtual void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) = 0;
- virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
- virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) = 0;
- virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) = 0;
- virtual void compute_list_add_barrier(ComputeListID p_list) = 0;
+ template <class T>
+ void _free_rids(T &p_owner, const char *p_type);
- virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0;
+ void _finalize_command_bufers();
+ void _begin_frame();
- virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS) = 0;
- virtual void full_barrier() = 0;
+#ifdef DEV_ENABLED
+ HashMap<RID, String> resource_names;
+#endif
- /***************/
- /**** FREE! ****/
- /***************/
+public:
+ void initialize(ApiContextRD *p_context, bool p_local_device = false);
+ void finalize();
- virtual void free(RID p_id) = 0;
+ void free(RID p_id);
/****************/
/**** Timing ****/
/****************/
- virtual void capture_timestamp(const String &p_name) = 0;
- virtual uint32_t get_captured_timestamps_count() const = 0;
- virtual uint64_t get_captured_timestamps_frame() const = 0;
- virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0;
- virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0;
- virtual String get_captured_timestamp_name(uint32_t p_index) const = 0;
+ void capture_timestamp(const String &p_name);
+ uint32_t get_captured_timestamps_count() const;
+ uint64_t get_captured_timestamps_frame() const;
+ uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const;
+ uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
+ String get_captured_timestamp_name(uint32_t p_index) const;
/****************/
/**** LIMITS ****/
/****************/
- 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,
- };
-
- virtual uint64_t limit_get(Limit p_limit) const = 0;
+ uint64_t limit_get(Limit p_limit) const;
//methods below not exposed, used by RenderingDeviceRD
- virtual void prepare_screen_for_drawing() = 0;
+ void prepare_screen_for_drawing();
- virtual void swap_buffers() = 0;
+ void swap_buffers();
- virtual uint32_t get_frame_delay() const = 0;
+ uint32_t get_frame_delay() const;
- virtual void submit() = 0;
- virtual void sync() = 0;
+ void submit();
+ void sync();
enum MemoryType {
MEMORY_TEXTURES,
@@ -1312,33 +1304,34 @@ public:
MEMORY_TOTAL
};
- virtual uint64_t get_memory_usage(MemoryType p_type) const = 0;
+ uint64_t get_memory_usage(MemoryType p_type) const;
- virtual RenderingDevice *create_local_device() = 0;
+ RenderingDevice *create_local_device();
- virtual void set_resource_name(RID p_id, const String p_name) = 0;
+ 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)) = 0;
- virtual void draw_command_insert_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1)) = 0;
- virtual void draw_command_end_label() = 0;
+ void draw_command_begin_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1));
+ void draw_command_insert_label(String p_label_name, const Color &p_color = Color(1, 1, 1, 1));
+ void draw_command_end_label();
- virtual String get_device_vendor_name() const = 0;
- virtual String get_device_name() const = 0;
- virtual RenderingDevice::DeviceType get_device_type() const = 0;
- virtual String get_device_api_version() const = 0;
- virtual String get_device_pipeline_cache_uuid() const = 0;
+ String get_device_vendor_name() const;
+ String get_device_name() const;
+ DeviceType get_device_type() const;
+ String get_device_api_version() const;
+ 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) = 0;
+ uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
static RenderingDevice *get_singleton();
- RenderingDevice();
-protected:
- static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX];
+ RenderingDevice();
+ ~RenderingDevice();
- static const uint32_t MAX_UNIFORM_SETS = 16;
+private:
+ /*****************/
+ /**** BINDERS ****/
+ /*****************/
- //binders to script API
RID _texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data = Array());
RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture);
RID _texture_create_shared_from_slice(const Ref<RDTextureView> &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);
@@ -1348,7 +1341,9 @@ protected:
FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count);
RID _framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
RID _framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
+
RID _sampler_create(const Ref<RDSamplerState> &p_state);
+
VertexFormatID _vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats);
RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets = Vector<int64_t>());
@@ -1358,7 +1353,7 @@ protected:
RID _uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
- Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
@@ -1368,46 +1363,6 @@ protected:
void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits);
-
- struct SpirvReflectionData {
- BitField<ShaderStage> stages_mask;
- uint64_t vertex_input_mask;
- uint32_t fragment_output_mask;
- bool is_compute;
- uint32_t compute_local_size[3];
- uint32_t push_constant_size;
- BitField<ShaderStage> push_constant_stages_mask;
-
- struct Uniform {
- UniformType type;
- uint32_t binding;
- BitField<ShaderStage> stages_mask;
- uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
- bool writable;
- };
- Vector<Vector<Uniform>> uniforms;
-
- struct SpecializationConstant {
- PipelineSpecializationConstantType type;
- uint32_t constant_id;
- union {
- uint32_t int_value;
- float float_value;
- bool bool_value;
- };
- BitField<ShaderStage> stages_mask;
- };
- Vector<SpecializationConstant> specialization_constants;
- };
-
- Error _reflect_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, SpirvReflectionData &r_reflection_data);
-
-#ifndef DISABLE_DEPRECATED
- BitField<BarrierMask> _convert_barrier_mask_81356(BitField<BarrierMask> p_old_barrier);
- void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
- void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
- void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to);
-#endif
};
VARIANT_ENUM_CAST(RenderingDevice::DeviceType)
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index 737a874abc..5f21207579 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/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);
}
}
diff --git a/servers/rendering/rendering_device_commons.cpp b/servers/rendering/rendering_device_commons.cpp
new file mode 100644
index 0000000000..c8b7980633
--- /dev/null
+++ b/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",
+};
diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h
new file mode 100644
index 0000000000..dabd0c0867
--- /dev/null
+++ b/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
diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp
new file mode 100644
index 0000000000..9e05a6a133
--- /dev/null
+++ b/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() {}
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
new file mode 100644
index 0000000000..bb71a29bbc
--- /dev/null
+++ b/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
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 57bb5b3a52..7bc40601a0 100644
--- a/thirdparty/README.md
+++ b/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
diff --git a/thirdparty/d3d12ma/D3D12MemAlloc.cpp b/thirdparty/d3d12ma/D3D12MemAlloc.cpp
index 8e2488091a..4d19e0e727 100644
--- a/thirdparty/d3d12ma/D3D12MemAlloc.cpp
+++ b/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__
diff --git a/thirdparty/directx_headers/d3dx12.h b/thirdparty/directx_headers/d3dx12.h
deleted file mode 100644
index bbe273d333..0000000000
--- a/thirdparty/directx_headers/d3dx12.h
+++ /dev/null
@@ -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__
-
diff --git a/thirdparty/directx_headers/include/directx/D3D12TokenizedProgramFormat.hpp b/thirdparty/directx_headers/include/directx/D3D12TokenizedProgramFormat.hpp
new file mode 100644
index 0000000000..4d04c3a7a5
--- /dev/null
+++ b/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
diff --git a/thirdparty/directx_headers/d3d12.h b/thirdparty/directx_headers/include/directx/d3d12.h
index 07355f558c..d57513b7f8 100644
--- a/thirdparty/directx_headers/d3d12.h
+++ b/thirdparty/directx_headers/include/directx/d3d12.h
@@ -437,6 +437,20 @@ typedef interface ID3D12Device11 ID3D12Device11;
#endif /* __ID3D12Device11_FWD_DEFINED__ */
+#ifndef __ID3D12Device12_FWD_DEFINED__
+#define __ID3D12Device12_FWD_DEFINED__
+typedef interface ID3D12Device12 ID3D12Device12;
+
+#endif /* __ID3D12Device12_FWD_DEFINED__ */
+
+
+#ifndef __ID3D12Device13_FWD_DEFINED__
+#define __ID3D12Device13_FWD_DEFINED__
+typedef interface ID3D12Device13 ID3D12Device13;
+
+#endif /* __ID3D12Device13_FWD_DEFINED__ */
+
+
#ifndef __ID3D12VirtualizationGuestDevice_FWD_DEFINED__
#define __ID3D12VirtualizationGuestDevice_FWD_DEFINED__
typedef interface ID3D12VirtualizationGuestDevice ID3D12VirtualizationGuestDevice;
@@ -507,6 +521,13 @@ typedef interface ID3D12GraphicsCommandList8 ID3D12GraphicsCommandList8;
#endif /* __ID3D12GraphicsCommandList8_FWD_DEFINED__ */
+#ifndef __ID3D12GraphicsCommandList9_FWD_DEFINED__
+#define __ID3D12GraphicsCommandList9_FWD_DEFINED__
+typedef interface ID3D12GraphicsCommandList9 ID3D12GraphicsCommandList9;
+
+#endif /* __ID3D12GraphicsCommandList9_FWD_DEFINED__ */
+
+
/* header files for imported files */
#include "oaidl.h"
#include "ocidl.h"
@@ -1039,7 +1060,7 @@ extern "C"{
#define D3D12_PIXEL_ADDRESS_RANGE_BIT_COUNT ( 15 )
-#define D3D12_PREVIEW_SDK_VERSION ( 706 )
+#define D3D12_PREVIEW_SDK_VERSION ( 712 )
#define D3D12_PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT ( 16 )
@@ -1172,7 +1193,7 @@ extern "C"{
#define D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT ( 2 )
-#define D3D12_SDK_VERSION ( 606 )
+#define D3D12_SDK_VERSION ( 611 )
#define D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES ( 32 )
@@ -1290,6 +1311,16 @@ extern "C"{
#define D3D12_VIDEO_DECODE_STATUS_MACROBLOCKS_AFFECTED_UNKNOWN ( 0xffffffff )
+#define D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX ( 0xff )
+
+#define D3D12_VIDEO_ENCODER_AV1_MAX_TILE_COLS ( 64 )
+
+#define D3D12_VIDEO_ENCODER_AV1_MAX_TILE_ROWS ( 64 )
+
+#define D3D12_VIDEO_ENCODER_AV1_SUPERRES_DENOM_MIN ( 9 )
+
+#define D3D12_VIDEO_ENCODER_AV1_SUPERRES_NUM ( 8 )
+
#define D3D12_VIDEO_PROCESS_MAX_FILTERS ( 32 )
#define D3D12_VIDEO_PROCESS_STEREO_VIEWS ( 2 )
@@ -1642,6 +1673,44 @@ typedef struct D3D12_RASTERIZER_DESC
D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;
} D3D12_RASTERIZER_DESC;
+typedef struct D3D12_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;
+ } D3D12_RASTERIZER_DESC1;
+
+typedef
+enum D3D12_LINE_RASTERIZATION_MODE
+ {
+ D3D12_LINE_RASTERIZATION_MODE_ALIASED = 0,
+ D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED = ( D3D12_LINE_RASTERIZATION_MODE_ALIASED + 1 ) ,
+ D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE = ( D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED + 1 ) ,
+ D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_NARROW = ( D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE + 1 )
+ } D3D12_LINE_RASTERIZATION_MODE;
+
+typedef struct D3D12_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;
+ } D3D12_RASTERIZER_DESC2;
+
extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0000_v0_0_c_ifspec;
@@ -2058,7 +2127,9 @@ typedef
enum D3D12_PIPELINE_STATE_FLAGS
{
D3D12_PIPELINE_STATE_FLAG_NONE = 0,
- D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG = 0x1
+ D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG = 0x1,
+ D3D12_PIPELINE_STATE_FLAG_DYNAMIC_DEPTH_BIAS = 0x4,
+ D3D12_PIPELINE_STATE_FLAG_DYNAMIC_INDEX_BUFFER_STRIP_CUT = 0x8
} D3D12_PIPELINE_STATE_FLAGS;
DEFINE_ENUM_FLAG_OPERATORS( D3D12_PIPELINE_STATE_FLAGS );
@@ -2136,7 +2207,9 @@ enum D3D12_PIPELINE_STATE_SUBOBJECT_TYPE
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS = 24,
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS = 25,
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2 = 26,
- D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID = ( D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2 + 1 )
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1 = 27,
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2 = 28,
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID = ( D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2 + 1 )
} D3D12_PIPELINE_STATE_SUBOBJECT_TYPE;
typedef
@@ -2176,7 +2249,15 @@ enum D3D12_FEATURE
D3D12_FEATURE_D3D12_OPTIONS12 = 41,
D3D12_FEATURE_D3D12_OPTIONS13 = 42,
D3D12_FEATURE_D3D12_OPTIONS14 = 43,
- D3D12_FEATURE_D3D12_OPTIONS15 = 44
+ D3D12_FEATURE_D3D12_OPTIONS15 = 44,
+ D3D12_FEATURE_D3D12_OPTIONS16 = 45,
+ D3D12_FEATURE_D3D12_OPTIONS17 = 46,
+ D3D12_FEATURE_D3D12_OPTIONS18 = 47,
+ D3D12_FEATURE_D3D12_OPTIONS19 = 48,
+ D3D12_FEATURE_D3D12_OPTIONS20 = 49,
+ D3D12_FEATURE_PREDICATION = 50,
+ D3D12_FEATURE_PLACED_RESOURCE_SUPPORT_INFO = 51,
+ D3D12_FEATURE_HARDWARE_COPY = 52
} D3D12_FEATURE;
typedef
@@ -2352,7 +2433,8 @@ enum D3D_ROOT_SIGNATURE_VERSION
{
D3D_ROOT_SIGNATURE_VERSION_1 = 0x1,
D3D_ROOT_SIGNATURE_VERSION_1_0 = 0x1,
- D3D_ROOT_SIGNATURE_VERSION_1_1 = 0x2
+ D3D_ROOT_SIGNATURE_VERSION_1_1 = 0x2,
+ D3D_ROOT_SIGNATURE_VERSION_1_2 = 0x3
} D3D_ROOT_SIGNATURE_VERSION;
typedef struct D3D12_FEATURE_DATA_ROOT_SIGNATURE
@@ -2668,6 +2750,60 @@ typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS15
_Out_ BOOL DynamicIndexBufferStripCutSupported;
} D3D12_FEATURE_DATA_D3D12_OPTIONS15;
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS16
+ {
+ _Out_ BOOL DynamicDepthBiasSupported;
+ _Out_ BOOL GPUUploadHeapSupported;
+ } D3D12_FEATURE_DATA_D3D12_OPTIONS16;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS17
+ {
+ _Out_ BOOL NonNormalizedCoordinateSamplersSupported;
+ _Out_ BOOL ManualWriteTrackingResourceSupported;
+ } D3D12_FEATURE_DATA_D3D12_OPTIONS17;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS18
+ {
+ _Out_ BOOL RenderPassesValid;
+ } D3D12_FEATURE_DATA_D3D12_OPTIONS18;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS19
+ {
+ BOOL MismatchingOutputDimensionsSupported;
+ UINT SupportedSampleCountsWithNoOutputs;
+ BOOL PointSamplingAddressesNeverRoundUp;
+ BOOL RasterizerDesc2Supported;
+ BOOL NarrowQuadrilateralLinesSupported;
+ BOOL AnisoFilterWithPointMipSupported;
+ UINT MaxSamplerDescriptorHeapSize;
+ UINT MaxSamplerDescriptorHeapSizeWithStaticSamplers;
+ UINT MaxViewDescriptorHeapSize;
+ _Out_ BOOL ComputeOnlyCustomHeapSupported;
+ } D3D12_FEATURE_DATA_D3D12_OPTIONS19;
+
+typedef
+enum D3D12_RECREATE_AT_TIER
+ {
+ D3D12_RECREATE_AT_TIER_NOT_SUPPORTED = 0,
+ D3D12_RECREATE_AT_TIER_1 = 1
+ } D3D12_RECREATE_AT_TIER;
+
+typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS20
+ {
+ _Out_ BOOL ComputeOnlyWriteWatchSupported;
+ D3D12_RECREATE_AT_TIER RecreateAtTier;
+ } D3D12_FEATURE_DATA_D3D12_OPTIONS20;
+
+typedef struct D3D12_FEATURE_DATA_PREDICATION
+ {
+ _Out_ BOOL Supported;
+ } D3D12_FEATURE_DATA_PREDICATION;
+
+typedef struct D3D12_FEATURE_DATA_HARDWARE_COPY
+ {
+ _Out_ BOOL Supported;
+ } D3D12_FEATURE_DATA_HARDWARE_COPY;
+
typedef struct D3D12_RESOURCE_ALLOCATION_INFO
{
UINT64 SizeInBytes;
@@ -2687,7 +2823,8 @@ enum D3D12_HEAP_TYPE
D3D12_HEAP_TYPE_DEFAULT = 1,
D3D12_HEAP_TYPE_UPLOAD = 2,
D3D12_HEAP_TYPE_READBACK = 3,
- D3D12_HEAP_TYPE_CUSTOM = 4
+ D3D12_HEAP_TYPE_CUSTOM = 4,
+ D3D12_HEAP_TYPE_GPU_UPLOAD = 5
} D3D12_HEAP_TYPE;
typedef
@@ -2731,6 +2868,7 @@ enum D3D12_HEAP_FLAGS
D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS = 0x400,
D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT = 0x800,
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED = 0x1000,
+ D3D12_HEAP_FLAG_TOOLS_USE_MANUAL_WRITE_TRACKING = 0x2000,
D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES = 0,
D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS = 0xc0,
D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES = 0x44,
@@ -2756,6 +2894,14 @@ enum D3D12_RESOURCE_DIMENSION
D3D12_RESOURCE_DIMENSION_TEXTURE3D = 4
} D3D12_RESOURCE_DIMENSION;
+typedef struct D3D12_FEATURE_DATA_PLACED_RESOURCE_SUPPORT_INFO
+ {
+ _In_ DXGI_FORMAT Format;
+ _In_ D3D12_RESOURCE_DIMENSION Dimension;
+ _In_ D3D12_HEAP_PROPERTIES DestHeapProperties;
+ _Out_ BOOL Supported;
+ } D3D12_FEATURE_DATA_PLACED_RESOURCE_SUPPORT_INFO;
+
typedef
enum D3D12_TEXTURE_LAYOUT
{
@@ -2945,6 +3091,11 @@ enum D3D12_RESOURCE_STATES
D3D12_RESOURCE_STATE_RESOLVE_SOURCE = 0x2000,
D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE = 0x400000,
D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE = 0x1000000,
+ D3D12_RESOURCE_STATE_RESERVED_INTERNAL_8000 = 0x8000,
+ D3D12_RESOURCE_STATE_RESERVED_INTERNAL_4000 = 0x4000,
+ D3D12_RESOURCE_STATE_RESERVED_INTERNAL_100000 = 0x100000,
+ D3D12_RESOURCE_STATE_RESERVED_INTERNAL_40000000 = 0x40000000,
+ D3D12_RESOURCE_STATE_RESERVED_INTERNAL_80000000 = 0x80000000,
D3D12_RESOURCE_STATE_GENERIC_READ = ( ( ( ( ( 0x1 | 0x2 ) | 0x40 ) | 0x80 ) | 0x200 ) | 0x800 ) ,
D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE = ( 0x40 | 0x80 ) ,
D3D12_RESOURCE_STATE_PRESENT = 0,
@@ -3243,6 +3394,7 @@ enum D3D12_FILTER
D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11,
D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14,
D3D12_FILTER_MIN_MAG_MIP_LINEAR = 0x15,
+ D3D12_FILTER_MIN_MAG_ANISOTROPIC_MIP_POINT = 0x54,
D3D12_FILTER_ANISOTROPIC = 0x55,
D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80,
D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81,
@@ -3252,6 +3404,7 @@ enum D3D12_FILTER
D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91,
D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94,
D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95,
+ D3D12_FILTER_COMPARISON_MIN_MAG_ANISOTROPIC_MIP_POINT = 0xd4,
D3D12_FILTER_COMPARISON_ANISOTROPIC = 0xd5,
D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT = 0x100,
D3D12_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x101,
@@ -3261,6 +3414,7 @@ enum D3D12_FILTER
D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x111,
D3D12_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x114,
D3D12_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR = 0x115,
+ D3D12_FILTER_MINIMUM_MIN_MAG_ANISOTROPIC_MIP_POINT = 0x154,
D3D12_FILTER_MINIMUM_ANISOTROPIC = 0x155,
D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT = 0x180,
D3D12_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x181,
@@ -3270,6 +3424,7 @@ enum D3D12_FILTER
D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x191,
D3D12_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x194,
D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR = 0x195,
+ D3D12_FILTER_MAXIMUM_MIN_MAG_ANISOTROPIC_MIP_POINT = 0x1d4,
D3D12_FILTER_MAXIMUM_ANISOTROPIC = 0x1d5
} D3D12_FILTER;
@@ -3316,6 +3471,13 @@ enum D3D12_FILTER_REDUCTION_TYPE
D3D12_FILTER_TYPE_LINEAR, \
D3D12_FILTER_TYPE_LINEAR, \
reduction ) ) )
+#define D3D12_ENCODE_MIN_MAG_ANISOTROPIC_MIP_POINT_FILTER( reduction ) \
+ ( ( D3D12_FILTER ) ( \
+ D3D12_ANISOTROPIC_FILTERING_BIT | \
+ D3D12_ENCODE_BASIC_FILTER( D3D12_FILTER_TYPE_LINEAR, \
+ D3D12_FILTER_TYPE_LINEAR, \
+ D3D12_FILTER_TYPE_POINT, \
+ reduction ) ) )
#define D3D12_DECODE_MIN_FILTER( D3D12Filter ) \
( ( D3D12_FILTER_TYPE ) \
( ( ( D3D12Filter ) >> D3D12_MIN_FILTER_SHIFT ) & D3D12_FILTER_TYPE_MASK ) )
@@ -3333,8 +3495,7 @@ enum D3D12_FILTER_REDUCTION_TYPE
#define D3D12_DECODE_IS_ANISOTROPIC_FILTER( D3D12Filter ) \
( ( ( D3D12Filter ) & D3D12_ANISOTROPIC_FILTERING_BIT ) && \
( D3D12_FILTER_TYPE_LINEAR == D3D12_DECODE_MIN_FILTER( D3D12Filter ) ) && \
- ( D3D12_FILTER_TYPE_LINEAR == D3D12_DECODE_MAG_FILTER( D3D12Filter ) ) && \
- ( D3D12_FILTER_TYPE_LINEAR == D3D12_DECODE_MIP_FILTER( D3D12Filter ) ) )
+ ( D3D12_FILTER_TYPE_LINEAR == D3D12_DECODE_MAG_FILTER( D3D12Filter ) ) )
typedef
enum D3D12_TEXTURE_ADDRESS_MODE
{
@@ -3363,7 +3524,8 @@ typedef
enum D3D12_SAMPLER_FLAGS
{
D3D12_SAMPLER_FLAG_NONE = 0,
- D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR = 0x1
+ D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR = 0x1,
+ D3D12_SAMPLER_FLAG_NON_NORMALIZED_COORDINATES = 0x2
} D3D12_SAMPLER_FLAGS;
DEFINE_ENUM_FLAG_OPERATORS( D3D12_SAMPLER_FLAGS );
@@ -3793,6 +3955,24 @@ typedef struct D3D12_STATIC_SAMPLER_DESC
D3D12_SHADER_VISIBILITY ShaderVisibility;
} D3D12_STATIC_SAMPLER_DESC;
+typedef struct D3D12_STATIC_SAMPLER_DESC1
+ {
+ D3D12_FILTER Filter;
+ D3D12_TEXTURE_ADDRESS_MODE AddressU;
+ D3D12_TEXTURE_ADDRESS_MODE AddressV;
+ D3D12_TEXTURE_ADDRESS_MODE AddressW;
+ FLOAT MipLODBias;
+ UINT MaxAnisotropy;
+ D3D12_COMPARISON_FUNC ComparisonFunc;
+ D3D12_STATIC_BORDER_COLOR BorderColor;
+ FLOAT MinLOD;
+ FLOAT MaxLOD;
+ UINT ShaderRegister;
+ UINT RegisterSpace;
+ D3D12_SHADER_VISIBILITY ShaderVisibility;
+ D3D12_SAMPLER_FLAGS Flags;
+ } D3D12_STATIC_SAMPLER_DESC1;
+
typedef struct D3D12_ROOT_SIGNATURE_DESC
{
UINT NumParameters;
@@ -3868,6 +4048,15 @@ typedef struct D3D12_ROOT_SIGNATURE_DESC1
D3D12_ROOT_SIGNATURE_FLAGS Flags;
} D3D12_ROOT_SIGNATURE_DESC1;
+typedef struct D3D12_ROOT_SIGNATURE_DESC2
+ {
+ UINT NumParameters;
+ _Field_size_full_(NumParameters) const D3D12_ROOT_PARAMETER1 *pParameters;
+ UINT NumStaticSamplers;
+ _Field_size_full_(NumStaticSamplers) const D3D12_STATIC_SAMPLER_DESC1 *pStaticSamplers;
+ D3D12_ROOT_SIGNATURE_FLAGS Flags;
+ } D3D12_ROOT_SIGNATURE_DESC2;
+
typedef struct D3D12_VERSIONED_ROOT_SIGNATURE_DESC
{
D3D_ROOT_SIGNATURE_VERSION Version;
@@ -3875,6 +4064,7 @@ typedef struct D3D12_VERSIONED_ROOT_SIGNATURE_DESC
{
D3D12_ROOT_SIGNATURE_DESC Desc_1_0;
D3D12_ROOT_SIGNATURE_DESC1 Desc_1_1;
+ D3D12_ROOT_SIGNATURE_DESC2 Desc_1_2;
} ;
} D3D12_VERSIONED_ROOT_SIGNATURE_DESC;
@@ -13535,14 +13725,14 @@ typedef struct D3D12_DXIL_LIBRARY_DESC
{
D3D12_SHADER_BYTECODE DXILLibrary;
UINT NumExports;
- _In_reads_(NumExports) D3D12_EXPORT_DESC *pExports;
+ _In_reads_(NumExports) const D3D12_EXPORT_DESC *pExports;
} D3D12_DXIL_LIBRARY_DESC;
typedef struct D3D12_EXISTING_COLLECTION_DESC
{
ID3D12StateObject *pExistingCollection;
UINT NumExports;
- _In_reads_(NumExports) D3D12_EXPORT_DESC *pExports;
+ _In_reads_(NumExports) const D3D12_EXPORT_DESC *pExports;
} D3D12_EXISTING_COLLECTION_DESC;
typedef struct D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION
@@ -14760,7 +14950,9 @@ enum D3D12_AUTO_BREADCRUMB_OP
D3D12_AUTO_BREADCRUMB_OP_EXECUTEEXTENSIONCOMMAND = 41,
D3D12_AUTO_BREADCRUMB_OP_DISPATCHMESH = 42,
D3D12_AUTO_BREADCRUMB_OP_ENCODEFRAME = 43,
- D3D12_AUTO_BREADCRUMB_OP_RESOLVEENCODEROUTPUTMETADATA = 44
+ D3D12_AUTO_BREADCRUMB_OP_RESOLVEENCODEROUTPUTMETADATA = 44,
+ D3D12_AUTO_BREADCRUMB_OP_BARRIER = 45,
+ D3D12_AUTO_BREADCRUMB_OP_BEGIN_COMMAND_LIST = 46
} D3D12_AUTO_BREADCRUMB_OP;
typedef struct D3D12_AUTO_BREADCRUMB_NODE
@@ -19808,7 +20000,10 @@ enum D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD = 0,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD + 1 ) ,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE + 1 ) ,
- D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR + 1 )
+ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR + 1 ) ,
+ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS + 1 ) ,
+ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_SRV = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER + 1 ) ,
+ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_UAV = ( D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_SRV + 1 )
} D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE;
typedef struct D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
@@ -19816,12 +20011,19 @@ typedef struct D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
D3D12_CLEAR_VALUE ClearValue;
} D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS;
+typedef struct D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS
+ {
+ UINT AdditionalWidth;
+ UINT AdditionalHeight;
+ } D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS;
+
typedef struct D3D12_RENDER_PASS_BEGINNING_ACCESS
{
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE Type;
union
{
D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS Clear;
+ D3D12_RENDER_PASS_BEGINNING_ACCESS_PRESERVE_LOCAL_PARAMETERS PreserveLocal;
} ;
} D3D12_RENDER_PASS_BEGINNING_ACCESS;
@@ -19831,7 +20033,10 @@ enum D3D12_RENDER_PASS_ENDING_ACCESS_TYPE
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD = 0,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD + 1 ) ,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE + 1 ) ,
- D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE + 1 )
+ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE + 1 ) ,
+ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS + 1 ) ,
+ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_SRV = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER + 1 ) ,
+ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_UAV = ( D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_SRV + 1 )
} D3D12_RENDER_PASS_ENDING_ACCESS_TYPE;
typedef struct D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS
@@ -19854,12 +20059,19 @@ typedef struct D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS
BOOL PreserveResolveSource;
} D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS;
+typedef struct D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS
+ {
+ UINT AdditionalWidth;
+ UINT AdditionalHeight;
+ } D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS;
+
typedef struct D3D12_RENDER_PASS_ENDING_ACCESS
{
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE Type;
union
{
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS Resolve;
+ D3D12_RENDER_PASS_ENDING_ACCESS_PRESERVE_LOCAL_PARAMETERS PreserveLocal;
} ;
} D3D12_RENDER_PASS_ENDING_ACCESS;
@@ -19885,7 +20097,9 @@ enum D3D12_RENDER_PASS_FLAGS
D3D12_RENDER_PASS_FLAG_NONE = 0,
D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES = 0x1,
D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS = 0x2,
- D3D12_RENDER_PASS_FLAG_RESUMING_PASS = 0x4
+ D3D12_RENDER_PASS_FLAG_RESUMING_PASS = 0x4,
+ D3D12_RENDER_PASS_FLAG_BIND_READ_ONLY_DEPTH = 0x8,
+ D3D12_RENDER_PASS_FLAG_BIND_READ_ONLY_STENCIL = 0x10
} D3D12_RENDER_PASS_FLAGS;
DEFINE_ENUM_FLAG_OPERATORS( D3D12_RENDER_PASS_FLAGS );
@@ -20968,7 +21182,7 @@ enum D3D12_BARRIER_SYNC
D3D12_BARRIER_SYNC_NONE = 0,
D3D12_BARRIER_SYNC_ALL = 0x1,
D3D12_BARRIER_SYNC_DRAW = 0x2,
- D3D12_BARRIER_SYNC_INPUT_ASSEMBLER = 0x4,
+ D3D12_BARRIER_SYNC_INDEX_INPUT = 0x4,
D3D12_BARRIER_SYNC_VERTEX_SHADING = 0x8,
D3D12_BARRIER_SYNC_PIXEL_SHADING = 0x10,
D3D12_BARRIER_SYNC_DEPTH_STENCIL = 0x20,
@@ -22299,7 +22513,7 @@ EXTERN_C const IID IID_ID3D12Device10;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riidResource,
_COM_Outptr_opt_ void **ppvResource) = 0;
@@ -22310,7 +22524,7 @@ EXTERN_C const IID IID_ID3D12Device10;
D3D12_BARRIER_LAYOUT InitialLayout,
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource) = 0;
@@ -22320,7 +22534,7 @@ EXTERN_C const IID IID_ID3D12Device10;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource) = 0;
@@ -22968,7 +23182,7 @@ EXTERN_C const IID IID_ID3D12Device10;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riidResource,
_COM_Outptr_opt_ void **ppvResource);
@@ -22981,7 +23195,7 @@ EXTERN_C const IID IID_ID3D12Device10;
D3D12_BARRIER_LAYOUT InitialLayout,
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource);
@@ -22993,7 +23207,7 @@ EXTERN_C const IID IID_ID3D12Device10;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource);
@@ -23958,7 +24172,7 @@ EXTERN_C const IID IID_ID3D12Device11;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riidResource,
_COM_Outptr_opt_ void **ppvResource);
@@ -23971,7 +24185,7 @@ EXTERN_C const IID IID_ID3D12Device11;
D3D12_BARRIER_LAYOUT InitialLayout,
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource);
@@ -23983,7 +24197,7 @@ EXTERN_C const IID IID_ID3D12Device11;
_In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
_In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
UINT32 NumCastableFormats,
- _In_opt_count_(NumCastableFormats) DXGI_FORMAT *pCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
REFIID riid,
_COM_Outptr_opt_ void **ppvResource);
@@ -24295,6 +24509,2101 @@ EXTERN_C const IID IID_ID3D12Device11;
#endif /* __ID3D12Device11_INTERFACE_DEFINED__ */
+#ifndef __ID3D12Device12_INTERFACE_DEFINED__
+#define __ID3D12Device12_INTERFACE_DEFINED__
+
+/* interface ID3D12Device12 */
+/* [unique][local][object][uuid] */
+
+
+EXTERN_C const IID IID_ID3D12Device12;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5af5c532-4c91-4cd0-b541-15a405395fc5")
+ ID3D12Device12 : public ID3D12Device11
+ {
+ public:
+#if defined(_MSC_VER) || !defined(_WIN32)
+ virtual D3D12_RESOURCE_ALLOCATION_INFO STDMETHODCALLTYPE GetResourceAllocationInfo3(
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1) = 0;
+#else
+ virtual D3D12_RESOURCE_ALLOCATION_INFO *STDMETHODCALLTYPE GetResourceAllocationInfo3(
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1) = 0;
+#endif
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ID3D12Device12Vtbl
+ {
+ BEGIN_INTERFACE
+
+ DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ID3D12Device12 * This,
+ REFIID riid,
+ _COM_Outptr_ void **ppvObject);
+
+ DECLSPEC_XFGVIRT(IUnknown, AddRef)
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ID3D12Device12 * This);
+
+ DECLSPEC_XFGVIRT(IUnknown, Release)
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ID3D12Device12 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, GetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *GetPrivateData )(
+ ID3D12Device12 * This,
+ _In_ REFGUID guid,
+ _Inout_ UINT *pDataSize,
+ _Out_writes_bytes_opt_( *pDataSize ) void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateData )(
+ ID3D12Device12 * This,
+ _In_ REFGUID guid,
+ _In_ UINT DataSize,
+ _In_reads_bytes_opt_( DataSize ) const void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateDataInterface)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )(
+ ID3D12Device12 * This,
+ _In_ REFGUID guid,
+ _In_opt_ const IUnknown *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetName)
+ HRESULT ( STDMETHODCALLTYPE *SetName )(
+ ID3D12Device12 * This,
+ _In_z_ LPCWSTR Name);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetNodeCount)
+ UINT ( STDMETHODCALLTYPE *GetNodeCount )(
+ ID3D12Device12 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandQueue)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandQueue )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_COMMAND_QUEUE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandQueue);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandAllocator)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandAllocator )(
+ ID3D12Device12 * This,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandAllocator);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateGraphicsPipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreateGraphicsPipelineState )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateComputePipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreateComputePipelineState )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_COMPUTE_PIPELINE_STATE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandList)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandList )(
+ ID3D12Device12 * This,
+ _In_ UINT nodeMask,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ _In_ ID3D12CommandAllocator *pCommandAllocator,
+ _In_opt_ ID3D12PipelineState *pInitialState,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandList);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CheckFeatureSupport)
+ HRESULT ( STDMETHODCALLTYPE *CheckFeatureSupport )(
+ ID3D12Device12 * This,
+ D3D12_FEATURE Feature,
+ _Inout_updates_bytes_(FeatureSupportDataSize) void *pFeatureSupportData,
+ UINT FeatureSupportDataSize);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateDescriptorHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateDescriptorHeap )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_DESCRIPTOR_HEAP_DESC *pDescriptorHeapDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetDescriptorHandleIncrementSize)
+ UINT ( STDMETHODCALLTYPE *GetDescriptorHandleIncrementSize )(
+ ID3D12Device12 * This,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateRootSignature)
+ HRESULT ( STDMETHODCALLTYPE *CreateRootSignature )(
+ ID3D12Device12 * This,
+ _In_ UINT nodeMask,
+ _In_reads_(blobLengthInBytes) const void *pBlobWithRootSignature,
+ _In_ SIZE_T blobLengthInBytes,
+ REFIID riid,
+ _COM_Outptr_ void **ppvRootSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateConstantBufferView)
+ void ( STDMETHODCALLTYPE *CreateConstantBufferView )(
+ ID3D12Device12 * This,
+ _In_opt_ const D3D12_CONSTANT_BUFFER_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateShaderResourceView)
+ void ( STDMETHODCALLTYPE *CreateShaderResourceView )(
+ ID3D12Device12 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_SHADER_RESOURCE_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *CreateUnorderedAccessView )(
+ ID3D12Device12 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ ID3D12Resource *pCounterResource,
+ _In_opt_ const D3D12_UNORDERED_ACCESS_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateRenderTargetView)
+ void ( STDMETHODCALLTYPE *CreateRenderTargetView )(
+ ID3D12Device12 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_RENDER_TARGET_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateDepthStencilView)
+ void ( STDMETHODCALLTYPE *CreateDepthStencilView )(
+ ID3D12Device12 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_DEPTH_STENCIL_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateSampler)
+ void ( STDMETHODCALLTYPE *CreateSampler )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_SAMPLER_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CopyDescriptors)
+ void ( STDMETHODCALLTYPE *CopyDescriptors )(
+ ID3D12Device12 * This,
+ _In_ UINT NumDestDescriptorRanges,
+ _In_reads_(NumDestDescriptorRanges) const D3D12_CPU_DESCRIPTOR_HANDLE *pDestDescriptorRangeStarts,
+ _In_reads_opt_(NumDestDescriptorRanges) const UINT *pDestDescriptorRangeSizes,
+ _In_ UINT NumSrcDescriptorRanges,
+ _In_reads_(NumSrcDescriptorRanges) const D3D12_CPU_DESCRIPTOR_HANDLE *pSrcDescriptorRangeStarts,
+ _In_reads_opt_(NumSrcDescriptorRanges) const UINT *pSrcDescriptorRangeSizes,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CopyDescriptorsSimple)
+ void ( STDMETHODCALLTYPE *CopyDescriptorsSimple )(
+ ID3D12Device12 * This,
+ _In_ UINT NumDescriptors,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetResourceAllocationInfo)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo )(
+ ID3D12Device12 * This,
+ _In_ UINT visibleMask,
+ _In_ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo )(
+ ID3D12Device12 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ _In_ UINT visibleMask,
+ _In_ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetCustomHeapProperties)
+#if !defined(_WIN32)
+ D3D12_HEAP_PROPERTIES ( STDMETHODCALLTYPE *GetCustomHeapProperties )(
+ ID3D12Device12 * This,
+ _In_ UINT nodeMask,
+ D3D12_HEAP_TYPE heapType);
+
+#else
+ D3D12_HEAP_PROPERTIES *( STDMETHODCALLTYPE *GetCustomHeapProperties )(
+ ID3D12Device12 * This,
+ D3D12_HEAP_PROPERTIES * RetVal,
+ _In_ UINT nodeMask,
+ D3D12_HEAP_TYPE heapType);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommittedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateHeap )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreatePlacedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource )(
+ ID3D12Device12 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateReservedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateSharedHandle)
+ HRESULT ( STDMETHODCALLTYPE *CreateSharedHandle )(
+ ID3D12Device12 * This,
+ _In_ ID3D12DeviceChild *pObject,
+ _In_opt_ const SECURITY_ATTRIBUTES *pAttributes,
+ DWORD Access,
+ _In_opt_ LPCWSTR Name,
+ _Out_ HANDLE *pHandle);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, OpenSharedHandle)
+ HRESULT ( STDMETHODCALLTYPE *OpenSharedHandle )(
+ ID3D12Device12 * This,
+ _In_ HANDLE NTHandle,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvObj);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, OpenSharedHandleByName)
+ HRESULT ( STDMETHODCALLTYPE *OpenSharedHandleByName )(
+ ID3D12Device12 * This,
+ _In_ LPCWSTR Name,
+ DWORD Access,
+ /* [annotation][out] */
+ _Out_ HANDLE *pNTHandle);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, MakeResident)
+ HRESULT ( STDMETHODCALLTYPE *MakeResident )(
+ ID3D12Device12 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, Evict)
+ HRESULT ( STDMETHODCALLTYPE *Evict )(
+ ID3D12Device12 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateFence)
+ HRESULT ( STDMETHODCALLTYPE *CreateFence )(
+ ID3D12Device12 * This,
+ UINT64 InitialValue,
+ D3D12_FENCE_FLAGS Flags,
+ REFIID riid,
+ _COM_Outptr_ void **ppFence);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetDeviceRemovedReason)
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceRemovedReason )(
+ ID3D12Device12 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetCopyableFootprints)
+ void ( STDMETHODCALLTYPE *GetCopyableFootprints )(
+ ID3D12Device12 * This,
+ _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);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateQueryHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateQueryHeap )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_QUERY_HEAP_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, SetStablePowerState)
+ HRESULT ( STDMETHODCALLTYPE *SetStablePowerState )(
+ ID3D12Device12 * This,
+ BOOL Enable);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandSignature)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandSignature )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_COMMAND_SIGNATURE_DESC *pDesc,
+ _In_opt_ ID3D12RootSignature *pRootSignature,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvCommandSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetResourceTiling)
+ void ( STDMETHODCALLTYPE *GetResourceTiling )(
+ ID3D12Device12 * This,
+ _In_ ID3D12Resource *pTiledResource,
+ _Out_opt_ UINT *pNumTilesForEntireResource,
+ _Out_opt_ D3D12_PACKED_MIP_INFO *pPackedMipDesc,
+ _Out_opt_ D3D12_TILE_SHAPE *pStandardTileShapeForNonPackedMips,
+ _Inout_opt_ UINT *pNumSubresourceTilings,
+ _In_ UINT FirstSubresourceTilingToGet,
+ _Out_writes_(*pNumSubresourceTilings) D3D12_SUBRESOURCE_TILING *pSubresourceTilingsForNonPackedMips);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetAdapterLuid)
+#if !defined(_WIN32)
+ LUID ( STDMETHODCALLTYPE *GetAdapterLuid )(
+ ID3D12Device12 * This);
+
+#else
+ LUID *( STDMETHODCALLTYPE *GetAdapterLuid )(
+ ID3D12Device12 * This,
+ LUID * RetVal);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, CreatePipelineLibrary)
+ HRESULT ( STDMETHODCALLTYPE *CreatePipelineLibrary )(
+ ID3D12Device12 * This,
+ _In_reads_(BlobLength) const void *pLibraryBlob,
+ SIZE_T BlobLength,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineLibrary);
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, SetEventOnMultipleFenceCompletion)
+ HRESULT ( STDMETHODCALLTYPE *SetEventOnMultipleFenceCompletion )(
+ ID3D12Device12 * This,
+ _In_reads_(NumFences) ID3D12Fence *const *ppFences,
+ _In_reads_(NumFences) const UINT64 *pFenceValues,
+ UINT NumFences,
+ D3D12_MULTIPLE_FENCE_WAIT_FLAGS Flags,
+ HANDLE hEvent);
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, SetResidencyPriority)
+ HRESULT ( STDMETHODCALLTYPE *SetResidencyPriority )(
+ ID3D12Device12 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects,
+ _In_reads_(NumObjects) const D3D12_RESIDENCY_PRIORITY *pPriorities);
+
+ DECLSPEC_XFGVIRT(ID3D12Device2, CreatePipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreatePipelineState )(
+ ID3D12Device12 * This,
+ const D3D12_PIPELINE_STATE_STREAM_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, OpenExistingHeapFromAddress)
+ HRESULT ( STDMETHODCALLTYPE *OpenExistingHeapFromAddress )(
+ ID3D12Device12 * This,
+ _In_ const void *pAddress,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, OpenExistingHeapFromFileMapping)
+ HRESULT ( STDMETHODCALLTYPE *OpenExistingHeapFromFileMapping )(
+ ID3D12Device12 * This,
+ _In_ HANDLE hFileMapping,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, EnqueueMakeResident)
+ HRESULT ( STDMETHODCALLTYPE *EnqueueMakeResident )(
+ ID3D12Device12 * This,
+ D3D12_RESIDENCY_FLAGS Flags,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects,
+ _In_ ID3D12Fence *pFenceToSignal,
+ UINT64 FenceValueToSignal);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateCommandList1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandList1 )(
+ ID3D12Device12 * This,
+ _In_ UINT nodeMask,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ _In_ D3D12_COMMAND_LIST_FLAGS flags,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandList);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateProtectedResourceSession)
+ HRESULT ( STDMETHODCALLTYPE *CreateProtectedResourceSession )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_PROTECTED_RESOURCE_SESSION_DESC *pDesc,
+ _In_ REFIID riid,
+ _COM_Outptr_ void **ppSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateCommittedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateHeap1)
+ HRESULT ( STDMETHODCALLTYPE *CreateHeap1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_DESC *pDesc,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateReservedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, GetResourceAllocationInfo1)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo1 )(
+ ID3D12Device12 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo1 )(
+ ID3D12Device12 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateLifetimeTracker)
+ HRESULT ( STDMETHODCALLTYPE *CreateLifetimeTracker )(
+ ID3D12Device12 * This,
+ _In_ ID3D12LifetimeOwner *pOwner,
+ REFIID riid,
+ _COM_Outptr_ void **ppvTracker);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, RemoveDevice)
+ void ( STDMETHODCALLTYPE *RemoveDevice )(
+ ID3D12Device12 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, EnumerateMetaCommands)
+ HRESULT ( STDMETHODCALLTYPE *EnumerateMetaCommands )(
+ ID3D12Device12 * This,
+ _Inout_ UINT *pNumMetaCommands,
+ _Out_writes_opt_(*pNumMetaCommands) D3D12_META_COMMAND_DESC *pDescs);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, EnumerateMetaCommandParameters)
+ HRESULT ( STDMETHODCALLTYPE *EnumerateMetaCommandParameters )(
+ ID3D12Device12 * This,
+ _In_ REFGUID CommandId,
+ _In_ D3D12_META_COMMAND_PARAMETER_STAGE Stage,
+ _Out_opt_ UINT *pTotalStructureSizeInBytes,
+ _Inout_ UINT *pParameterCount,
+ _Out_writes_opt_(*pParameterCount) D3D12_META_COMMAND_PARAMETER_DESC *pParameterDescs);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateMetaCommand)
+ HRESULT ( STDMETHODCALLTYPE *CreateMetaCommand )(
+ ID3D12Device12 * This,
+ _In_ REFGUID CommandId,
+ _In_ UINT NodeMask,
+ _In_reads_bytes_opt_(CreationParametersDataSizeInBytes) const void *pCreationParametersData,
+ _In_ SIZE_T CreationParametersDataSizeInBytes,
+ REFIID riid,
+ _COM_Outptr_ void **ppMetaCommand);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateStateObject)
+ HRESULT ( STDMETHODCALLTYPE *CreateStateObject )(
+ ID3D12Device12 * This,
+ const D3D12_STATE_OBJECT_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppStateObject);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, GetRaytracingAccelerationStructurePrebuildInfo)
+ void ( STDMETHODCALLTYPE *GetRaytracingAccelerationStructurePrebuildInfo )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *pDesc,
+ _Out_ D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO *pInfo);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CheckDriverMatchingIdentifier)
+ D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS ( STDMETHODCALLTYPE *CheckDriverMatchingIdentifier )(
+ ID3D12Device12 * This,
+ _In_ D3D12_SERIALIZED_DATA_TYPE SerializedDataType,
+ _In_ const D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER *pIdentifierToCheck);
+
+ DECLSPEC_XFGVIRT(ID3D12Device6, SetBackgroundProcessingMode)
+ HRESULT ( STDMETHODCALLTYPE *SetBackgroundProcessingMode )(
+ ID3D12Device12 * This,
+ D3D12_BACKGROUND_PROCESSING_MODE Mode,
+ D3D12_MEASUREMENTS_ACTION MeasurementsAction,
+ _In_opt_ HANDLE hEventToSignalUponCompletion,
+ _Out_opt_ BOOL *pbFurtherMeasurementsDesired);
+
+ DECLSPEC_XFGVIRT(ID3D12Device7, AddToStateObject)
+ HRESULT ( STDMETHODCALLTYPE *AddToStateObject )(
+ ID3D12Device12 * This,
+ const D3D12_STATE_OBJECT_DESC *pAddition,
+ ID3D12StateObject *pStateObjectToGrowFrom,
+ REFIID riid,
+ _COM_Outptr_ void **ppNewStateObject);
+
+ DECLSPEC_XFGVIRT(ID3D12Device7, CreateProtectedResourceSession1)
+ HRESULT ( STDMETHODCALLTYPE *CreateProtectedResourceSession1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_PROTECTED_RESOURCE_SESSION_DESC1 *pDesc,
+ _In_ REFIID riid,
+ _COM_Outptr_ void **ppSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, GetResourceAllocationInfo2)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo2 )(
+ ID3D12Device12 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo2 )(
+ ID3D12Device12 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreateCommittedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource2 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreatePlacedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource1 )(
+ ID3D12Device12 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreateSamplerFeedbackUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *CreateSamplerFeedbackUnorderedAccessView )(
+ ID3D12Device12 * This,
+ _In_opt_ ID3D12Resource *pTargetedResource,
+ _In_opt_ ID3D12Resource *pFeedbackResource,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, GetCopyableFootprints1)
+ void ( STDMETHODCALLTYPE *GetCopyableFootprints1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_RESOURCE_DESC1 *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);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, CreateShaderCacheSession)
+ HRESULT ( STDMETHODCALLTYPE *CreateShaderCacheSession )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_SHADER_CACHE_SESSION_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, ShaderCacheControl)
+ HRESULT ( STDMETHODCALLTYPE *ShaderCacheControl )(
+ ID3D12Device12 * This,
+ D3D12_SHADER_CACHE_KIND_FLAGS Kinds,
+ D3D12_SHADER_CACHE_CONTROL_FLAGS Control);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, CreateCommandQueue1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandQueue1 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_COMMAND_QUEUE_DESC *pDesc,
+ REFIID CreatorID,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandQueue);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreateCommittedResource3)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource3 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreatePlacedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource2 )(
+ ID3D12Device12 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreateReservedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource2 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device11, CreateSampler2)
+ void ( STDMETHODCALLTYPE *CreateSampler2 )(
+ ID3D12Device12 * This,
+ _In_ const D3D12_SAMPLER_DESC2 *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device12, GetResourceAllocationInfo3)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo3 )(
+ ID3D12Device12 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo3 )(
+ ID3D12Device12 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ END_INTERFACE
+ } ID3D12Device12Vtbl;
+
+ interface ID3D12Device12
+ {
+ CONST_VTBL struct ID3D12Device12Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ID3D12Device12_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ID3D12Device12_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ID3D12Device12_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ID3D12Device12_GetPrivateData(This,guid,pDataSize,pData) \
+ ( (This)->lpVtbl -> GetPrivateData(This,guid,pDataSize,pData) )
+
+#define ID3D12Device12_SetPrivateData(This,guid,DataSize,pData) \
+ ( (This)->lpVtbl -> SetPrivateData(This,guid,DataSize,pData) )
+
+#define ID3D12Device12_SetPrivateDataInterface(This,guid,pData) \
+ ( (This)->lpVtbl -> SetPrivateDataInterface(This,guid,pData) )
+
+#define ID3D12Device12_SetName(This,Name) \
+ ( (This)->lpVtbl -> SetName(This,Name) )
+
+
+#define ID3D12Device12_GetNodeCount(This) \
+ ( (This)->lpVtbl -> GetNodeCount(This) )
+
+#define ID3D12Device12_CreateCommandQueue(This,pDesc,riid,ppCommandQueue) \
+ ( (This)->lpVtbl -> CreateCommandQueue(This,pDesc,riid,ppCommandQueue) )
+
+#define ID3D12Device12_CreateCommandAllocator(This,type,riid,ppCommandAllocator) \
+ ( (This)->lpVtbl -> CreateCommandAllocator(This,type,riid,ppCommandAllocator) )
+
+#define ID3D12Device12_CreateGraphicsPipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreateGraphicsPipelineState(This,pDesc,riid,ppPipelineState) )
+
+#define ID3D12Device12_CreateComputePipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreateComputePipelineState(This,pDesc,riid,ppPipelineState) )
+
+#define ID3D12Device12_CreateCommandList(This,nodeMask,type,pCommandAllocator,pInitialState,riid,ppCommandList) \
+ ( (This)->lpVtbl -> CreateCommandList(This,nodeMask,type,pCommandAllocator,pInitialState,riid,ppCommandList) )
+
+#define ID3D12Device12_CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) \
+ ( (This)->lpVtbl -> CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) )
+
+#define ID3D12Device12_CreateDescriptorHeap(This,pDescriptorHeapDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateDescriptorHeap(This,pDescriptorHeapDesc,riid,ppvHeap) )
+
+#define ID3D12Device12_GetDescriptorHandleIncrementSize(This,DescriptorHeapType) \
+ ( (This)->lpVtbl -> GetDescriptorHandleIncrementSize(This,DescriptorHeapType) )
+
+#define ID3D12Device12_CreateRootSignature(This,nodeMask,pBlobWithRootSignature,blobLengthInBytes,riid,ppvRootSignature) \
+ ( (This)->lpVtbl -> CreateRootSignature(This,nodeMask,pBlobWithRootSignature,blobLengthInBytes,riid,ppvRootSignature) )
+
+#define ID3D12Device12_CreateConstantBufferView(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateConstantBufferView(This,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CreateShaderResourceView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateShaderResourceView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CreateUnorderedAccessView(This,pResource,pCounterResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateUnorderedAccessView(This,pResource,pCounterResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CreateRenderTargetView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateRenderTargetView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CreateDepthStencilView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateDepthStencilView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CreateSampler(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSampler(This,pDesc,DestDescriptor) )
+
+#define ID3D12Device12_CopyDescriptors(This,NumDestDescriptorRanges,pDestDescriptorRangeStarts,pDestDescriptorRangeSizes,NumSrcDescriptorRanges,pSrcDescriptorRangeStarts,pSrcDescriptorRangeSizes,DescriptorHeapsType) \
+ ( (This)->lpVtbl -> CopyDescriptors(This,NumDestDescriptorRanges,pDestDescriptorRangeStarts,pDestDescriptorRangeSizes,NumSrcDescriptorRanges,pSrcDescriptorRangeStarts,pSrcDescriptorRangeSizes,DescriptorHeapsType) )
+
+#define ID3D12Device12_CopyDescriptorsSimple(This,NumDescriptors,DestDescriptorRangeStart,SrcDescriptorRangeStart,DescriptorHeapsType) \
+ ( (This)->lpVtbl -> CopyDescriptorsSimple(This,NumDescriptors,DestDescriptorRangeStart,SrcDescriptorRangeStart,DescriptorHeapsType) )
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetResourceAllocationInfo(This,visibleMask,numResourceDescs,pResourceDescs) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo(This,visibleMask,numResourceDescs,pResourceDescs) )
+#else
+#define ID3D12Device12_GetResourceAllocationInfo(This,RetVal,visibleMask,numResourceDescs,pResourceDescs) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo(This,RetVal,visibleMask,numResourceDescs,pResourceDescs) )
+#endif
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetCustomHeapProperties(This,nodeMask,heapType) \
+ ( (This)->lpVtbl -> GetCustomHeapProperties(This,nodeMask,heapType) )
+#else
+#define ID3D12Device12_GetCustomHeapProperties(This,RetVal,nodeMask,heapType) \
+ ( (This)->lpVtbl -> GetCustomHeapProperties(This,RetVal,nodeMask,heapType) )
+#endif
+
+#define ID3D12Device12_CreateCommittedResource(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,riidResource,ppvResource) )
+
+#define ID3D12Device12_CreateHeap(This,pDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateHeap(This,pDesc,riid,ppvHeap) )
+
+#define ID3D12Device12_CreatePlacedResource(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device12_CreateReservedResource(This,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource(This,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device12_CreateSharedHandle(This,pObject,pAttributes,Access,Name,pHandle) \
+ ( (This)->lpVtbl -> CreateSharedHandle(This,pObject,pAttributes,Access,Name,pHandle) )
+
+#define ID3D12Device12_OpenSharedHandle(This,NTHandle,riid,ppvObj) \
+ ( (This)->lpVtbl -> OpenSharedHandle(This,NTHandle,riid,ppvObj) )
+
+#define ID3D12Device12_OpenSharedHandleByName(This,Name,Access,pNTHandle) \
+ ( (This)->lpVtbl -> OpenSharedHandleByName(This,Name,Access,pNTHandle) )
+
+#define ID3D12Device12_MakeResident(This,NumObjects,ppObjects) \
+ ( (This)->lpVtbl -> MakeResident(This,NumObjects,ppObjects) )
+
+#define ID3D12Device12_Evict(This,NumObjects,ppObjects) \
+ ( (This)->lpVtbl -> Evict(This,NumObjects,ppObjects) )
+
+#define ID3D12Device12_CreateFence(This,InitialValue,Flags,riid,ppFence) \
+ ( (This)->lpVtbl -> CreateFence(This,InitialValue,Flags,riid,ppFence) )
+
+#define ID3D12Device12_GetDeviceRemovedReason(This) \
+ ( (This)->lpVtbl -> GetDeviceRemovedReason(This) )
+
+#define ID3D12Device12_GetCopyableFootprints(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) \
+ ( (This)->lpVtbl -> GetCopyableFootprints(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) )
+
+#define ID3D12Device12_CreateQueryHeap(This,pDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateQueryHeap(This,pDesc,riid,ppvHeap) )
+
+#define ID3D12Device12_SetStablePowerState(This,Enable) \
+ ( (This)->lpVtbl -> SetStablePowerState(This,Enable) )
+
+#define ID3D12Device12_CreateCommandSignature(This,pDesc,pRootSignature,riid,ppvCommandSignature) \
+ ( (This)->lpVtbl -> CreateCommandSignature(This,pDesc,pRootSignature,riid,ppvCommandSignature) )
+
+#define ID3D12Device12_GetResourceTiling(This,pTiledResource,pNumTilesForEntireResource,pPackedMipDesc,pStandardTileShapeForNonPackedMips,pNumSubresourceTilings,FirstSubresourceTilingToGet,pSubresourceTilingsForNonPackedMips) \
+ ( (This)->lpVtbl -> GetResourceTiling(This,pTiledResource,pNumTilesForEntireResource,pPackedMipDesc,pStandardTileShapeForNonPackedMips,pNumSubresourceTilings,FirstSubresourceTilingToGet,pSubresourceTilingsForNonPackedMips) )
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetAdapterLuid(This) \
+ ( (This)->lpVtbl -> GetAdapterLuid(This) )
+#else
+#define ID3D12Device12_GetAdapterLuid(This,RetVal) \
+ ( (This)->lpVtbl -> GetAdapterLuid(This,RetVal) )
+#endif
+
+
+#define ID3D12Device12_CreatePipelineLibrary(This,pLibraryBlob,BlobLength,riid,ppPipelineLibrary) \
+ ( (This)->lpVtbl -> CreatePipelineLibrary(This,pLibraryBlob,BlobLength,riid,ppPipelineLibrary) )
+
+#define ID3D12Device12_SetEventOnMultipleFenceCompletion(This,ppFences,pFenceValues,NumFences,Flags,hEvent) \
+ ( (This)->lpVtbl -> SetEventOnMultipleFenceCompletion(This,ppFences,pFenceValues,NumFences,Flags,hEvent) )
+
+#define ID3D12Device12_SetResidencyPriority(This,NumObjects,ppObjects,pPriorities) \
+ ( (This)->lpVtbl -> SetResidencyPriority(This,NumObjects,ppObjects,pPriorities) )
+
+
+#define ID3D12Device12_CreatePipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreatePipelineState(This,pDesc,riid,ppPipelineState) )
+
+
+#define ID3D12Device12_OpenExistingHeapFromAddress(This,pAddress,riid,ppvHeap) \
+ ( (This)->lpVtbl -> OpenExistingHeapFromAddress(This,pAddress,riid,ppvHeap) )
+
+#define ID3D12Device12_OpenExistingHeapFromFileMapping(This,hFileMapping,riid,ppvHeap) \
+ ( (This)->lpVtbl -> OpenExistingHeapFromFileMapping(This,hFileMapping,riid,ppvHeap) )
+
+#define ID3D12Device12_EnqueueMakeResident(This,Flags,NumObjects,ppObjects,pFenceToSignal,FenceValueToSignal) \
+ ( (This)->lpVtbl -> EnqueueMakeResident(This,Flags,NumObjects,ppObjects,pFenceToSignal,FenceValueToSignal) )
+
+
+#define ID3D12Device12_CreateCommandList1(This,nodeMask,type,flags,riid,ppCommandList) \
+ ( (This)->lpVtbl -> CreateCommandList1(This,nodeMask,type,flags,riid,ppCommandList) )
+
+#define ID3D12Device12_CreateProtectedResourceSession(This,pDesc,riid,ppSession) \
+ ( (This)->lpVtbl -> CreateProtectedResourceSession(This,pDesc,riid,ppSession) )
+
+#define ID3D12Device12_CreateCommittedResource1(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource1(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) )
+
+#define ID3D12Device12_CreateHeap1(This,pDesc,pProtectedSession,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateHeap1(This,pDesc,pProtectedSession,riid,ppvHeap) )
+
+#define ID3D12Device12_CreateReservedResource1(This,pDesc,InitialState,pOptimizedClearValue,pProtectedSession,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource1(This,pDesc,InitialState,pOptimizedClearValue,pProtectedSession,riid,ppvResource) )
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetResourceAllocationInfo1(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo1(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device12_GetResourceAllocationInfo1(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo1(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#endif
+
+
+#define ID3D12Device12_CreateLifetimeTracker(This,pOwner,riid,ppvTracker) \
+ ( (This)->lpVtbl -> CreateLifetimeTracker(This,pOwner,riid,ppvTracker) )
+
+#define ID3D12Device12_RemoveDevice(This) \
+ ( (This)->lpVtbl -> RemoveDevice(This) )
+
+#define ID3D12Device12_EnumerateMetaCommands(This,pNumMetaCommands,pDescs) \
+ ( (This)->lpVtbl -> EnumerateMetaCommands(This,pNumMetaCommands,pDescs) )
+
+#define ID3D12Device12_EnumerateMetaCommandParameters(This,CommandId,Stage,pTotalStructureSizeInBytes,pParameterCount,pParameterDescs) \
+ ( (This)->lpVtbl -> EnumerateMetaCommandParameters(This,CommandId,Stage,pTotalStructureSizeInBytes,pParameterCount,pParameterDescs) )
+
+#define ID3D12Device12_CreateMetaCommand(This,CommandId,NodeMask,pCreationParametersData,CreationParametersDataSizeInBytes,riid,ppMetaCommand) \
+ ( (This)->lpVtbl -> CreateMetaCommand(This,CommandId,NodeMask,pCreationParametersData,CreationParametersDataSizeInBytes,riid,ppMetaCommand) )
+
+#define ID3D12Device12_CreateStateObject(This,pDesc,riid,ppStateObject) \
+ ( (This)->lpVtbl -> CreateStateObject(This,pDesc,riid,ppStateObject) )
+
+#define ID3D12Device12_GetRaytracingAccelerationStructurePrebuildInfo(This,pDesc,pInfo) \
+ ( (This)->lpVtbl -> GetRaytracingAccelerationStructurePrebuildInfo(This,pDesc,pInfo) )
+
+#define ID3D12Device12_CheckDriverMatchingIdentifier(This,SerializedDataType,pIdentifierToCheck) \
+ ( (This)->lpVtbl -> CheckDriverMatchingIdentifier(This,SerializedDataType,pIdentifierToCheck) )
+
+
+#define ID3D12Device12_SetBackgroundProcessingMode(This,Mode,MeasurementsAction,hEventToSignalUponCompletion,pbFurtherMeasurementsDesired) \
+ ( (This)->lpVtbl -> SetBackgroundProcessingMode(This,Mode,MeasurementsAction,hEventToSignalUponCompletion,pbFurtherMeasurementsDesired) )
+
+
+#define ID3D12Device12_AddToStateObject(This,pAddition,pStateObjectToGrowFrom,riid,ppNewStateObject) \
+ ( (This)->lpVtbl -> AddToStateObject(This,pAddition,pStateObjectToGrowFrom,riid,ppNewStateObject) )
+
+#define ID3D12Device12_CreateProtectedResourceSession1(This,pDesc,riid,ppSession) \
+ ( (This)->lpVtbl -> CreateProtectedResourceSession1(This,pDesc,riid,ppSession) )
+
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetResourceAllocationInfo2(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo2(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device12_GetResourceAllocationInfo2(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo2(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#endif
+
+#define ID3D12Device12_CreateCommittedResource2(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource2(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) )
+
+#define ID3D12Device12_CreatePlacedResource1(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource1(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device12_CreateSamplerFeedbackUnorderedAccessView(This,pTargetedResource,pFeedbackResource,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSamplerFeedbackUnorderedAccessView(This,pTargetedResource,pFeedbackResource,DestDescriptor) )
+
+#define ID3D12Device12_GetCopyableFootprints1(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) \
+ ( (This)->lpVtbl -> GetCopyableFootprints1(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) )
+
+
+#define ID3D12Device12_CreateShaderCacheSession(This,pDesc,riid,ppvSession) \
+ ( (This)->lpVtbl -> CreateShaderCacheSession(This,pDesc,riid,ppvSession) )
+
+#define ID3D12Device12_ShaderCacheControl(This,Kinds,Control) \
+ ( (This)->lpVtbl -> ShaderCacheControl(This,Kinds,Control) )
+
+#define ID3D12Device12_CreateCommandQueue1(This,pDesc,CreatorID,riid,ppCommandQueue) \
+ ( (This)->lpVtbl -> CreateCommandQueue1(This,pDesc,CreatorID,riid,ppCommandQueue) )
+
+
+#define ID3D12Device12_CreateCommittedResource3(This,pHeapProperties,HeapFlags,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource3(This,pHeapProperties,HeapFlags,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riidResource,ppvResource) )
+
+#define ID3D12Device12_CreatePlacedResource2(This,pHeap,HeapOffset,pDesc,InitialLayout,pOptimizedClearValue,NumCastableFormats,pCastableFormats,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource2(This,pHeap,HeapOffset,pDesc,InitialLayout,pOptimizedClearValue,NumCastableFormats,pCastableFormats,riid,ppvResource) )
+
+#define ID3D12Device12_CreateReservedResource2(This,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource2(This,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riid,ppvResource) )
+
+
+#define ID3D12Device12_CreateSampler2(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSampler2(This,pDesc,DestDescriptor) )
+
+#if !defined(_WIN32)
+
+#define ID3D12Device12_GetResourceAllocationInfo3(This,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo3(This,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device12_GetResourceAllocationInfo3(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo3(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) )
+#endif
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ID3D12Device12_INTERFACE_DEFINED__ */
+
+
+#ifndef __ID3D12Device13_INTERFACE_DEFINED__
+#define __ID3D12Device13_INTERFACE_DEFINED__
+
+/* interface ID3D12Device13 */
+/* [unique][local][object][uuid] */
+
+
+EXTERN_C const IID IID_ID3D12Device13;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("14eecffc-4df8-40f7-a118-5c816f45695e")
+ ID3D12Device13 : public ID3D12Device12
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenExistingHeapFromAddress1(
+ _In_ const void *pAddress,
+ SIZE_T size,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ID3D12Device13Vtbl
+ {
+ BEGIN_INTERFACE
+
+ DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ID3D12Device13 * This,
+ REFIID riid,
+ _COM_Outptr_ void **ppvObject);
+
+ DECLSPEC_XFGVIRT(IUnknown, AddRef)
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ID3D12Device13 * This);
+
+ DECLSPEC_XFGVIRT(IUnknown, Release)
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ID3D12Device13 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, GetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *GetPrivateData )(
+ ID3D12Device13 * This,
+ _In_ REFGUID guid,
+ _Inout_ UINT *pDataSize,
+ _Out_writes_bytes_opt_( *pDataSize ) void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateData )(
+ ID3D12Device13 * This,
+ _In_ REFGUID guid,
+ _In_ UINT DataSize,
+ _In_reads_bytes_opt_( DataSize ) const void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateDataInterface)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )(
+ ID3D12Device13 * This,
+ _In_ REFGUID guid,
+ _In_opt_ const IUnknown *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetName)
+ HRESULT ( STDMETHODCALLTYPE *SetName )(
+ ID3D12Device13 * This,
+ _In_z_ LPCWSTR Name);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetNodeCount)
+ UINT ( STDMETHODCALLTYPE *GetNodeCount )(
+ ID3D12Device13 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandQueue)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandQueue )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_COMMAND_QUEUE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandQueue);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandAllocator)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandAllocator )(
+ ID3D12Device13 * This,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandAllocator);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateGraphicsPipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreateGraphicsPipelineState )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateComputePipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreateComputePipelineState )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_COMPUTE_PIPELINE_STATE_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandList)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandList )(
+ ID3D12Device13 * This,
+ _In_ UINT nodeMask,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ _In_ ID3D12CommandAllocator *pCommandAllocator,
+ _In_opt_ ID3D12PipelineState *pInitialState,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandList);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CheckFeatureSupport)
+ HRESULT ( STDMETHODCALLTYPE *CheckFeatureSupport )(
+ ID3D12Device13 * This,
+ D3D12_FEATURE Feature,
+ _Inout_updates_bytes_(FeatureSupportDataSize) void *pFeatureSupportData,
+ UINT FeatureSupportDataSize);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateDescriptorHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateDescriptorHeap )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_DESCRIPTOR_HEAP_DESC *pDescriptorHeapDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetDescriptorHandleIncrementSize)
+ UINT ( STDMETHODCALLTYPE *GetDescriptorHandleIncrementSize )(
+ ID3D12Device13 * This,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateRootSignature)
+ HRESULT ( STDMETHODCALLTYPE *CreateRootSignature )(
+ ID3D12Device13 * This,
+ _In_ UINT nodeMask,
+ _In_reads_(blobLengthInBytes) const void *pBlobWithRootSignature,
+ _In_ SIZE_T blobLengthInBytes,
+ REFIID riid,
+ _COM_Outptr_ void **ppvRootSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateConstantBufferView)
+ void ( STDMETHODCALLTYPE *CreateConstantBufferView )(
+ ID3D12Device13 * This,
+ _In_opt_ const D3D12_CONSTANT_BUFFER_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateShaderResourceView)
+ void ( STDMETHODCALLTYPE *CreateShaderResourceView )(
+ ID3D12Device13 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_SHADER_RESOURCE_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *CreateUnorderedAccessView )(
+ ID3D12Device13 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ ID3D12Resource *pCounterResource,
+ _In_opt_ const D3D12_UNORDERED_ACCESS_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateRenderTargetView)
+ void ( STDMETHODCALLTYPE *CreateRenderTargetView )(
+ ID3D12Device13 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_RENDER_TARGET_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateDepthStencilView)
+ void ( STDMETHODCALLTYPE *CreateDepthStencilView )(
+ ID3D12Device13 * This,
+ _In_opt_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_DEPTH_STENCIL_VIEW_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateSampler)
+ void ( STDMETHODCALLTYPE *CreateSampler )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_SAMPLER_DESC *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CopyDescriptors)
+ void ( STDMETHODCALLTYPE *CopyDescriptors )(
+ ID3D12Device13 * This,
+ _In_ UINT NumDestDescriptorRanges,
+ _In_reads_(NumDestDescriptorRanges) const D3D12_CPU_DESCRIPTOR_HANDLE *pDestDescriptorRangeStarts,
+ _In_reads_opt_(NumDestDescriptorRanges) const UINT *pDestDescriptorRangeSizes,
+ _In_ UINT NumSrcDescriptorRanges,
+ _In_reads_(NumSrcDescriptorRanges) const D3D12_CPU_DESCRIPTOR_HANDLE *pSrcDescriptorRangeStarts,
+ _In_reads_opt_(NumSrcDescriptorRanges) const UINT *pSrcDescriptorRangeSizes,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CopyDescriptorsSimple)
+ void ( STDMETHODCALLTYPE *CopyDescriptorsSimple )(
+ ID3D12Device13 * This,
+ _In_ UINT NumDescriptors,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart,
+ _In_ D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetResourceAllocationInfo)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo )(
+ ID3D12Device13 * This,
+ _In_ UINT visibleMask,
+ _In_ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo )(
+ ID3D12Device13 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ _In_ UINT visibleMask,
+ _In_ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetCustomHeapProperties)
+#if !defined(_WIN32)
+ D3D12_HEAP_PROPERTIES ( STDMETHODCALLTYPE *GetCustomHeapProperties )(
+ ID3D12Device13 * This,
+ _In_ UINT nodeMask,
+ D3D12_HEAP_TYPE heapType);
+
+#else
+ D3D12_HEAP_PROPERTIES *( STDMETHODCALLTYPE *GetCustomHeapProperties )(
+ ID3D12Device13 * This,
+ D3D12_HEAP_PROPERTIES * RetVal,
+ _In_ UINT nodeMask,
+ D3D12_HEAP_TYPE heapType);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommittedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateHeap )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreatePlacedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource )(
+ ID3D12Device13 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateReservedResource)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateSharedHandle)
+ HRESULT ( STDMETHODCALLTYPE *CreateSharedHandle )(
+ ID3D12Device13 * This,
+ _In_ ID3D12DeviceChild *pObject,
+ _In_opt_ const SECURITY_ATTRIBUTES *pAttributes,
+ DWORD Access,
+ _In_opt_ LPCWSTR Name,
+ _Out_ HANDLE *pHandle);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, OpenSharedHandle)
+ HRESULT ( STDMETHODCALLTYPE *OpenSharedHandle )(
+ ID3D12Device13 * This,
+ _In_ HANDLE NTHandle,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvObj);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, OpenSharedHandleByName)
+ HRESULT ( STDMETHODCALLTYPE *OpenSharedHandleByName )(
+ ID3D12Device13 * This,
+ _In_ LPCWSTR Name,
+ DWORD Access,
+ /* [annotation][out] */
+ _Out_ HANDLE *pNTHandle);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, MakeResident)
+ HRESULT ( STDMETHODCALLTYPE *MakeResident )(
+ ID3D12Device13 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, Evict)
+ HRESULT ( STDMETHODCALLTYPE *Evict )(
+ ID3D12Device13 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateFence)
+ HRESULT ( STDMETHODCALLTYPE *CreateFence )(
+ ID3D12Device13 * This,
+ UINT64 InitialValue,
+ D3D12_FENCE_FLAGS Flags,
+ REFIID riid,
+ _COM_Outptr_ void **ppFence);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetDeviceRemovedReason)
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceRemovedReason )(
+ ID3D12Device13 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetCopyableFootprints)
+ void ( STDMETHODCALLTYPE *GetCopyableFootprints )(
+ ID3D12Device13 * This,
+ _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);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateQueryHeap)
+ HRESULT ( STDMETHODCALLTYPE *CreateQueryHeap )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_QUERY_HEAP_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, SetStablePowerState)
+ HRESULT ( STDMETHODCALLTYPE *SetStablePowerState )(
+ ID3D12Device13 * This,
+ BOOL Enable);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, CreateCommandSignature)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandSignature )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_COMMAND_SIGNATURE_DESC *pDesc,
+ _In_opt_ ID3D12RootSignature *pRootSignature,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvCommandSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetResourceTiling)
+ void ( STDMETHODCALLTYPE *GetResourceTiling )(
+ ID3D12Device13 * This,
+ _In_ ID3D12Resource *pTiledResource,
+ _Out_opt_ UINT *pNumTilesForEntireResource,
+ _Out_opt_ D3D12_PACKED_MIP_INFO *pPackedMipDesc,
+ _Out_opt_ D3D12_TILE_SHAPE *pStandardTileShapeForNonPackedMips,
+ _Inout_opt_ UINT *pNumSubresourceTilings,
+ _In_ UINT FirstSubresourceTilingToGet,
+ _Out_writes_(*pNumSubresourceTilings) D3D12_SUBRESOURCE_TILING *pSubresourceTilingsForNonPackedMips);
+
+ DECLSPEC_XFGVIRT(ID3D12Device, GetAdapterLuid)
+#if !defined(_WIN32)
+ LUID ( STDMETHODCALLTYPE *GetAdapterLuid )(
+ ID3D12Device13 * This);
+
+#else
+ LUID *( STDMETHODCALLTYPE *GetAdapterLuid )(
+ ID3D12Device13 * This,
+ LUID * RetVal);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, CreatePipelineLibrary)
+ HRESULT ( STDMETHODCALLTYPE *CreatePipelineLibrary )(
+ ID3D12Device13 * This,
+ _In_reads_(BlobLength) const void *pLibraryBlob,
+ SIZE_T BlobLength,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineLibrary);
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, SetEventOnMultipleFenceCompletion)
+ HRESULT ( STDMETHODCALLTYPE *SetEventOnMultipleFenceCompletion )(
+ ID3D12Device13 * This,
+ _In_reads_(NumFences) ID3D12Fence *const *ppFences,
+ _In_reads_(NumFences) const UINT64 *pFenceValues,
+ UINT NumFences,
+ D3D12_MULTIPLE_FENCE_WAIT_FLAGS Flags,
+ HANDLE hEvent);
+
+ DECLSPEC_XFGVIRT(ID3D12Device1, SetResidencyPriority)
+ HRESULT ( STDMETHODCALLTYPE *SetResidencyPriority )(
+ ID3D12Device13 * This,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects,
+ _In_reads_(NumObjects) const D3D12_RESIDENCY_PRIORITY *pPriorities);
+
+ DECLSPEC_XFGVIRT(ID3D12Device2, CreatePipelineState)
+ HRESULT ( STDMETHODCALLTYPE *CreatePipelineState )(
+ ID3D12Device13 * This,
+ const D3D12_PIPELINE_STATE_STREAM_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, OpenExistingHeapFromAddress)
+ HRESULT ( STDMETHODCALLTYPE *OpenExistingHeapFromAddress )(
+ ID3D12Device13 * This,
+ _In_ const void *pAddress,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, OpenExistingHeapFromFileMapping)
+ HRESULT ( STDMETHODCALLTYPE *OpenExistingHeapFromFileMapping )(
+ ID3D12Device13 * This,
+ _In_ HANDLE hFileMapping,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device3, EnqueueMakeResident)
+ HRESULT ( STDMETHODCALLTYPE *EnqueueMakeResident )(
+ ID3D12Device13 * This,
+ D3D12_RESIDENCY_FLAGS Flags,
+ UINT NumObjects,
+ _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects,
+ _In_ ID3D12Fence *pFenceToSignal,
+ UINT64 FenceValueToSignal);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateCommandList1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandList1 )(
+ ID3D12Device13 * This,
+ _In_ UINT nodeMask,
+ _In_ D3D12_COMMAND_LIST_TYPE type,
+ _In_ D3D12_COMMAND_LIST_FLAGS flags,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandList);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateProtectedResourceSession)
+ HRESULT ( STDMETHODCALLTYPE *CreateProtectedResourceSession )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_PROTECTED_RESOURCE_SESSION_DESC *pDesc,
+ _In_ REFIID riid,
+ _COM_Outptr_ void **ppSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateCommittedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateHeap1)
+ HRESULT ( STDMETHODCALLTYPE *CreateHeap1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_DESC *pDesc,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvHeap);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, CreateReservedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device4, GetResourceAllocationInfo1)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo1 )(
+ ID3D12Device13 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo1 )(
+ ID3D12Device13 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateLifetimeTracker)
+ HRESULT ( STDMETHODCALLTYPE *CreateLifetimeTracker )(
+ ID3D12Device13 * This,
+ _In_ ID3D12LifetimeOwner *pOwner,
+ REFIID riid,
+ _COM_Outptr_ void **ppvTracker);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, RemoveDevice)
+ void ( STDMETHODCALLTYPE *RemoveDevice )(
+ ID3D12Device13 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, EnumerateMetaCommands)
+ HRESULT ( STDMETHODCALLTYPE *EnumerateMetaCommands )(
+ ID3D12Device13 * This,
+ _Inout_ UINT *pNumMetaCommands,
+ _Out_writes_opt_(*pNumMetaCommands) D3D12_META_COMMAND_DESC *pDescs);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, EnumerateMetaCommandParameters)
+ HRESULT ( STDMETHODCALLTYPE *EnumerateMetaCommandParameters )(
+ ID3D12Device13 * This,
+ _In_ REFGUID CommandId,
+ _In_ D3D12_META_COMMAND_PARAMETER_STAGE Stage,
+ _Out_opt_ UINT *pTotalStructureSizeInBytes,
+ _Inout_ UINT *pParameterCount,
+ _Out_writes_opt_(*pParameterCount) D3D12_META_COMMAND_PARAMETER_DESC *pParameterDescs);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateMetaCommand)
+ HRESULT ( STDMETHODCALLTYPE *CreateMetaCommand )(
+ ID3D12Device13 * This,
+ _In_ REFGUID CommandId,
+ _In_ UINT NodeMask,
+ _In_reads_bytes_opt_(CreationParametersDataSizeInBytes) const void *pCreationParametersData,
+ _In_ SIZE_T CreationParametersDataSizeInBytes,
+ REFIID riid,
+ _COM_Outptr_ void **ppMetaCommand);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CreateStateObject)
+ HRESULT ( STDMETHODCALLTYPE *CreateStateObject )(
+ ID3D12Device13 * This,
+ const D3D12_STATE_OBJECT_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_ void **ppStateObject);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, GetRaytracingAccelerationStructurePrebuildInfo)
+ void ( STDMETHODCALLTYPE *GetRaytracingAccelerationStructurePrebuildInfo )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *pDesc,
+ _Out_ D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO *pInfo);
+
+ DECLSPEC_XFGVIRT(ID3D12Device5, CheckDriverMatchingIdentifier)
+ D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS ( STDMETHODCALLTYPE *CheckDriverMatchingIdentifier )(
+ ID3D12Device13 * This,
+ _In_ D3D12_SERIALIZED_DATA_TYPE SerializedDataType,
+ _In_ const D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER *pIdentifierToCheck);
+
+ DECLSPEC_XFGVIRT(ID3D12Device6, SetBackgroundProcessingMode)
+ HRESULT ( STDMETHODCALLTYPE *SetBackgroundProcessingMode )(
+ ID3D12Device13 * This,
+ D3D12_BACKGROUND_PROCESSING_MODE Mode,
+ D3D12_MEASUREMENTS_ACTION MeasurementsAction,
+ _In_opt_ HANDLE hEventToSignalUponCompletion,
+ _Out_opt_ BOOL *pbFurtherMeasurementsDesired);
+
+ DECLSPEC_XFGVIRT(ID3D12Device7, AddToStateObject)
+ HRESULT ( STDMETHODCALLTYPE *AddToStateObject )(
+ ID3D12Device13 * This,
+ const D3D12_STATE_OBJECT_DESC *pAddition,
+ ID3D12StateObject *pStateObjectToGrowFrom,
+ REFIID riid,
+ _COM_Outptr_ void **ppNewStateObject);
+
+ DECLSPEC_XFGVIRT(ID3D12Device7, CreateProtectedResourceSession1)
+ HRESULT ( STDMETHODCALLTYPE *CreateProtectedResourceSession1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_PROTECTED_RESOURCE_SESSION_DESC1 *pDesc,
+ _In_ REFIID riid,
+ _COM_Outptr_ void **ppSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, GetResourceAllocationInfo2)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo2 )(
+ ID3D12Device13 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo2 )(
+ ID3D12Device13 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreateCommittedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource2 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreatePlacedResource1)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource1 )(
+ ID3D12Device13 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_RESOURCE_STATES InitialState,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, CreateSamplerFeedbackUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *CreateSamplerFeedbackUnorderedAccessView )(
+ ID3D12Device13 * This,
+ _In_opt_ ID3D12Resource *pTargetedResource,
+ _In_opt_ ID3D12Resource *pFeedbackResource,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device8, GetCopyableFootprints1)
+ void ( STDMETHODCALLTYPE *GetCopyableFootprints1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_RESOURCE_DESC1 *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);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, CreateShaderCacheSession)
+ HRESULT ( STDMETHODCALLTYPE *CreateShaderCacheSession )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_SHADER_CACHE_SESSION_DESC *pDesc,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvSession);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, ShaderCacheControl)
+ HRESULT ( STDMETHODCALLTYPE *ShaderCacheControl )(
+ ID3D12Device13 * This,
+ D3D12_SHADER_CACHE_KIND_FLAGS Kinds,
+ D3D12_SHADER_CACHE_CONTROL_FLAGS Control);
+
+ DECLSPEC_XFGVIRT(ID3D12Device9, CreateCommandQueue1)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommandQueue1 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_COMMAND_QUEUE_DESC *pDesc,
+ REFIID CreatorID,
+ REFIID riid,
+ _COM_Outptr_ void **ppCommandQueue);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreateCommittedResource3)
+ HRESULT ( STDMETHODCALLTYPE *CreateCommittedResource3 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_HEAP_PROPERTIES *pHeapProperties,
+ D3D12_HEAP_FLAGS HeapFlags,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riidResource,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreatePlacedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreatePlacedResource2 )(
+ ID3D12Device13 * This,
+ _In_ ID3D12Heap *pHeap,
+ UINT64 HeapOffset,
+ _In_ const D3D12_RESOURCE_DESC1 *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device10, CreateReservedResource2)
+ HRESULT ( STDMETHODCALLTYPE *CreateReservedResource2 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_RESOURCE_DESC *pDesc,
+ D3D12_BARRIER_LAYOUT InitialLayout,
+ _In_opt_ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedSession,
+ UINT32 NumCastableFormats,
+ _In_opt_count_(NumCastableFormats) const DXGI_FORMAT *pCastableFormats,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvResource);
+
+ DECLSPEC_XFGVIRT(ID3D12Device11, CreateSampler2)
+ void ( STDMETHODCALLTYPE *CreateSampler2 )(
+ ID3D12Device13 * This,
+ _In_ const D3D12_SAMPLER_DESC2 *pDesc,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12Device12, GetResourceAllocationInfo3)
+#if !defined(_WIN32)
+ D3D12_RESOURCE_ALLOCATION_INFO ( STDMETHODCALLTYPE *GetResourceAllocationInfo3 )(
+ ID3D12Device13 * This,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#else
+ D3D12_RESOURCE_ALLOCATION_INFO *( STDMETHODCALLTYPE *GetResourceAllocationInfo3 )(
+ ID3D12Device13 * This,
+ D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
+ UINT visibleMask,
+ UINT numResourceDescs,
+ _In_reads_(numResourceDescs) const D3D12_RESOURCE_DESC1 *pResourceDescs,
+ _In_opt_count_(numResourceDescs) const UINT32 *pNumCastableFormats,
+ _In_opt_count_(numResourceDescs) const DXGI_FORMAT *const *ppCastableFormats,
+ _Out_writes_opt_(numResourceDescs) D3D12_RESOURCE_ALLOCATION_INFO1 *pResourceAllocationInfo1);
+
+#endif
+
+ DECLSPEC_XFGVIRT(ID3D12Device13, OpenExistingHeapFromAddress1)
+ HRESULT ( STDMETHODCALLTYPE *OpenExistingHeapFromAddress1 )(
+ ID3D12Device13 * This,
+ _In_ const void *pAddress,
+ SIZE_T size,
+ REFIID riid,
+ _COM_Outptr_ void **ppvHeap);
+
+ END_INTERFACE
+ } ID3D12Device13Vtbl;
+
+ interface ID3D12Device13
+ {
+ CONST_VTBL struct ID3D12Device13Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ID3D12Device13_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ID3D12Device13_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ID3D12Device13_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ID3D12Device13_GetPrivateData(This,guid,pDataSize,pData) \
+ ( (This)->lpVtbl -> GetPrivateData(This,guid,pDataSize,pData) )
+
+#define ID3D12Device13_SetPrivateData(This,guid,DataSize,pData) \
+ ( (This)->lpVtbl -> SetPrivateData(This,guid,DataSize,pData) )
+
+#define ID3D12Device13_SetPrivateDataInterface(This,guid,pData) \
+ ( (This)->lpVtbl -> SetPrivateDataInterface(This,guid,pData) )
+
+#define ID3D12Device13_SetName(This,Name) \
+ ( (This)->lpVtbl -> SetName(This,Name) )
+
+
+#define ID3D12Device13_GetNodeCount(This) \
+ ( (This)->lpVtbl -> GetNodeCount(This) )
+
+#define ID3D12Device13_CreateCommandQueue(This,pDesc,riid,ppCommandQueue) \
+ ( (This)->lpVtbl -> CreateCommandQueue(This,pDesc,riid,ppCommandQueue) )
+
+#define ID3D12Device13_CreateCommandAllocator(This,type,riid,ppCommandAllocator) \
+ ( (This)->lpVtbl -> CreateCommandAllocator(This,type,riid,ppCommandAllocator) )
+
+#define ID3D12Device13_CreateGraphicsPipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreateGraphicsPipelineState(This,pDesc,riid,ppPipelineState) )
+
+#define ID3D12Device13_CreateComputePipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreateComputePipelineState(This,pDesc,riid,ppPipelineState) )
+
+#define ID3D12Device13_CreateCommandList(This,nodeMask,type,pCommandAllocator,pInitialState,riid,ppCommandList) \
+ ( (This)->lpVtbl -> CreateCommandList(This,nodeMask,type,pCommandAllocator,pInitialState,riid,ppCommandList) )
+
+#define ID3D12Device13_CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) \
+ ( (This)->lpVtbl -> CheckFeatureSupport(This,Feature,pFeatureSupportData,FeatureSupportDataSize) )
+
+#define ID3D12Device13_CreateDescriptorHeap(This,pDescriptorHeapDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateDescriptorHeap(This,pDescriptorHeapDesc,riid,ppvHeap) )
+
+#define ID3D12Device13_GetDescriptorHandleIncrementSize(This,DescriptorHeapType) \
+ ( (This)->lpVtbl -> GetDescriptorHandleIncrementSize(This,DescriptorHeapType) )
+
+#define ID3D12Device13_CreateRootSignature(This,nodeMask,pBlobWithRootSignature,blobLengthInBytes,riid,ppvRootSignature) \
+ ( (This)->lpVtbl -> CreateRootSignature(This,nodeMask,pBlobWithRootSignature,blobLengthInBytes,riid,ppvRootSignature) )
+
+#define ID3D12Device13_CreateConstantBufferView(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateConstantBufferView(This,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CreateShaderResourceView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateShaderResourceView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CreateUnorderedAccessView(This,pResource,pCounterResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateUnorderedAccessView(This,pResource,pCounterResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CreateRenderTargetView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateRenderTargetView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CreateDepthStencilView(This,pResource,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateDepthStencilView(This,pResource,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CreateSampler(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSampler(This,pDesc,DestDescriptor) )
+
+#define ID3D12Device13_CopyDescriptors(This,NumDestDescriptorRanges,pDestDescriptorRangeStarts,pDestDescriptorRangeSizes,NumSrcDescriptorRanges,pSrcDescriptorRangeStarts,pSrcDescriptorRangeSizes,DescriptorHeapsType) \
+ ( (This)->lpVtbl -> CopyDescriptors(This,NumDestDescriptorRanges,pDestDescriptorRangeStarts,pDestDescriptorRangeSizes,NumSrcDescriptorRanges,pSrcDescriptorRangeStarts,pSrcDescriptorRangeSizes,DescriptorHeapsType) )
+
+#define ID3D12Device13_CopyDescriptorsSimple(This,NumDescriptors,DestDescriptorRangeStart,SrcDescriptorRangeStart,DescriptorHeapsType) \
+ ( (This)->lpVtbl -> CopyDescriptorsSimple(This,NumDescriptors,DestDescriptorRangeStart,SrcDescriptorRangeStart,DescriptorHeapsType) )
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetResourceAllocationInfo(This,visibleMask,numResourceDescs,pResourceDescs) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo(This,visibleMask,numResourceDescs,pResourceDescs) )
+#else
+#define ID3D12Device13_GetResourceAllocationInfo(This,RetVal,visibleMask,numResourceDescs,pResourceDescs) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo(This,RetVal,visibleMask,numResourceDescs,pResourceDescs) )
+#endif
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetCustomHeapProperties(This,nodeMask,heapType) \
+ ( (This)->lpVtbl -> GetCustomHeapProperties(This,nodeMask,heapType) )
+#else
+#define ID3D12Device13_GetCustomHeapProperties(This,RetVal,nodeMask,heapType) \
+ ( (This)->lpVtbl -> GetCustomHeapProperties(This,RetVal,nodeMask,heapType) )
+#endif
+
+#define ID3D12Device13_CreateCommittedResource(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,riidResource,ppvResource) )
+
+#define ID3D12Device13_CreateHeap(This,pDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateHeap(This,pDesc,riid,ppvHeap) )
+
+#define ID3D12Device13_CreatePlacedResource(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device13_CreateReservedResource(This,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource(This,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device13_CreateSharedHandle(This,pObject,pAttributes,Access,Name,pHandle) \
+ ( (This)->lpVtbl -> CreateSharedHandle(This,pObject,pAttributes,Access,Name,pHandle) )
+
+#define ID3D12Device13_OpenSharedHandle(This,NTHandle,riid,ppvObj) \
+ ( (This)->lpVtbl -> OpenSharedHandle(This,NTHandle,riid,ppvObj) )
+
+#define ID3D12Device13_OpenSharedHandleByName(This,Name,Access,pNTHandle) \
+ ( (This)->lpVtbl -> OpenSharedHandleByName(This,Name,Access,pNTHandle) )
+
+#define ID3D12Device13_MakeResident(This,NumObjects,ppObjects) \
+ ( (This)->lpVtbl -> MakeResident(This,NumObjects,ppObjects) )
+
+#define ID3D12Device13_Evict(This,NumObjects,ppObjects) \
+ ( (This)->lpVtbl -> Evict(This,NumObjects,ppObjects) )
+
+#define ID3D12Device13_CreateFence(This,InitialValue,Flags,riid,ppFence) \
+ ( (This)->lpVtbl -> CreateFence(This,InitialValue,Flags,riid,ppFence) )
+
+#define ID3D12Device13_GetDeviceRemovedReason(This) \
+ ( (This)->lpVtbl -> GetDeviceRemovedReason(This) )
+
+#define ID3D12Device13_GetCopyableFootprints(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) \
+ ( (This)->lpVtbl -> GetCopyableFootprints(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) )
+
+#define ID3D12Device13_CreateQueryHeap(This,pDesc,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateQueryHeap(This,pDesc,riid,ppvHeap) )
+
+#define ID3D12Device13_SetStablePowerState(This,Enable) \
+ ( (This)->lpVtbl -> SetStablePowerState(This,Enable) )
+
+#define ID3D12Device13_CreateCommandSignature(This,pDesc,pRootSignature,riid,ppvCommandSignature) \
+ ( (This)->lpVtbl -> CreateCommandSignature(This,pDesc,pRootSignature,riid,ppvCommandSignature) )
+
+#define ID3D12Device13_GetResourceTiling(This,pTiledResource,pNumTilesForEntireResource,pPackedMipDesc,pStandardTileShapeForNonPackedMips,pNumSubresourceTilings,FirstSubresourceTilingToGet,pSubresourceTilingsForNonPackedMips) \
+ ( (This)->lpVtbl -> GetResourceTiling(This,pTiledResource,pNumTilesForEntireResource,pPackedMipDesc,pStandardTileShapeForNonPackedMips,pNumSubresourceTilings,FirstSubresourceTilingToGet,pSubresourceTilingsForNonPackedMips) )
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetAdapterLuid(This) \
+ ( (This)->lpVtbl -> GetAdapterLuid(This) )
+#else
+#define ID3D12Device13_GetAdapterLuid(This,RetVal) \
+ ( (This)->lpVtbl -> GetAdapterLuid(This,RetVal) )
+#endif
+
+
+#define ID3D12Device13_CreatePipelineLibrary(This,pLibraryBlob,BlobLength,riid,ppPipelineLibrary) \
+ ( (This)->lpVtbl -> CreatePipelineLibrary(This,pLibraryBlob,BlobLength,riid,ppPipelineLibrary) )
+
+#define ID3D12Device13_SetEventOnMultipleFenceCompletion(This,ppFences,pFenceValues,NumFences,Flags,hEvent) \
+ ( (This)->lpVtbl -> SetEventOnMultipleFenceCompletion(This,ppFences,pFenceValues,NumFences,Flags,hEvent) )
+
+#define ID3D12Device13_SetResidencyPriority(This,NumObjects,ppObjects,pPriorities) \
+ ( (This)->lpVtbl -> SetResidencyPriority(This,NumObjects,ppObjects,pPriorities) )
+
+
+#define ID3D12Device13_CreatePipelineState(This,pDesc,riid,ppPipelineState) \
+ ( (This)->lpVtbl -> CreatePipelineState(This,pDesc,riid,ppPipelineState) )
+
+
+#define ID3D12Device13_OpenExistingHeapFromAddress(This,pAddress,riid,ppvHeap) \
+ ( (This)->lpVtbl -> OpenExistingHeapFromAddress(This,pAddress,riid,ppvHeap) )
+
+#define ID3D12Device13_OpenExistingHeapFromFileMapping(This,hFileMapping,riid,ppvHeap) \
+ ( (This)->lpVtbl -> OpenExistingHeapFromFileMapping(This,hFileMapping,riid,ppvHeap) )
+
+#define ID3D12Device13_EnqueueMakeResident(This,Flags,NumObjects,ppObjects,pFenceToSignal,FenceValueToSignal) \
+ ( (This)->lpVtbl -> EnqueueMakeResident(This,Flags,NumObjects,ppObjects,pFenceToSignal,FenceValueToSignal) )
+
+
+#define ID3D12Device13_CreateCommandList1(This,nodeMask,type,flags,riid,ppCommandList) \
+ ( (This)->lpVtbl -> CreateCommandList1(This,nodeMask,type,flags,riid,ppCommandList) )
+
+#define ID3D12Device13_CreateProtectedResourceSession(This,pDesc,riid,ppSession) \
+ ( (This)->lpVtbl -> CreateProtectedResourceSession(This,pDesc,riid,ppSession) )
+
+#define ID3D12Device13_CreateCommittedResource1(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource1(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) )
+
+#define ID3D12Device13_CreateHeap1(This,pDesc,pProtectedSession,riid,ppvHeap) \
+ ( (This)->lpVtbl -> CreateHeap1(This,pDesc,pProtectedSession,riid,ppvHeap) )
+
+#define ID3D12Device13_CreateReservedResource1(This,pDesc,InitialState,pOptimizedClearValue,pProtectedSession,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource1(This,pDesc,InitialState,pOptimizedClearValue,pProtectedSession,riid,ppvResource) )
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetResourceAllocationInfo1(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo1(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device13_GetResourceAllocationInfo1(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo1(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#endif
+
+
+#define ID3D12Device13_CreateLifetimeTracker(This,pOwner,riid,ppvTracker) \
+ ( (This)->lpVtbl -> CreateLifetimeTracker(This,pOwner,riid,ppvTracker) )
+
+#define ID3D12Device13_RemoveDevice(This) \
+ ( (This)->lpVtbl -> RemoveDevice(This) )
+
+#define ID3D12Device13_EnumerateMetaCommands(This,pNumMetaCommands,pDescs) \
+ ( (This)->lpVtbl -> EnumerateMetaCommands(This,pNumMetaCommands,pDescs) )
+
+#define ID3D12Device13_EnumerateMetaCommandParameters(This,CommandId,Stage,pTotalStructureSizeInBytes,pParameterCount,pParameterDescs) \
+ ( (This)->lpVtbl -> EnumerateMetaCommandParameters(This,CommandId,Stage,pTotalStructureSizeInBytes,pParameterCount,pParameterDescs) )
+
+#define ID3D12Device13_CreateMetaCommand(This,CommandId,NodeMask,pCreationParametersData,CreationParametersDataSizeInBytes,riid,ppMetaCommand) \
+ ( (This)->lpVtbl -> CreateMetaCommand(This,CommandId,NodeMask,pCreationParametersData,CreationParametersDataSizeInBytes,riid,ppMetaCommand) )
+
+#define ID3D12Device13_CreateStateObject(This,pDesc,riid,ppStateObject) \
+ ( (This)->lpVtbl -> CreateStateObject(This,pDesc,riid,ppStateObject) )
+
+#define ID3D12Device13_GetRaytracingAccelerationStructurePrebuildInfo(This,pDesc,pInfo) \
+ ( (This)->lpVtbl -> GetRaytracingAccelerationStructurePrebuildInfo(This,pDesc,pInfo) )
+
+#define ID3D12Device13_CheckDriverMatchingIdentifier(This,SerializedDataType,pIdentifierToCheck) \
+ ( (This)->lpVtbl -> CheckDriverMatchingIdentifier(This,SerializedDataType,pIdentifierToCheck) )
+
+
+#define ID3D12Device13_SetBackgroundProcessingMode(This,Mode,MeasurementsAction,hEventToSignalUponCompletion,pbFurtherMeasurementsDesired) \
+ ( (This)->lpVtbl -> SetBackgroundProcessingMode(This,Mode,MeasurementsAction,hEventToSignalUponCompletion,pbFurtherMeasurementsDesired) )
+
+
+#define ID3D12Device13_AddToStateObject(This,pAddition,pStateObjectToGrowFrom,riid,ppNewStateObject) \
+ ( (This)->lpVtbl -> AddToStateObject(This,pAddition,pStateObjectToGrowFrom,riid,ppNewStateObject) )
+
+#define ID3D12Device13_CreateProtectedResourceSession1(This,pDesc,riid,ppSession) \
+ ( (This)->lpVtbl -> CreateProtectedResourceSession1(This,pDesc,riid,ppSession) )
+
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetResourceAllocationInfo2(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo2(This,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device13_GetResourceAllocationInfo2(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo2(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pResourceAllocationInfo1) )
+#endif
+
+#define ID3D12Device13_CreateCommittedResource2(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource2(This,pHeapProperties,HeapFlags,pDesc,InitialResourceState,pOptimizedClearValue,pProtectedSession,riidResource,ppvResource) )
+
+#define ID3D12Device13_CreatePlacedResource1(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource1(This,pHeap,HeapOffset,pDesc,InitialState,pOptimizedClearValue,riid,ppvResource) )
+
+#define ID3D12Device13_CreateSamplerFeedbackUnorderedAccessView(This,pTargetedResource,pFeedbackResource,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSamplerFeedbackUnorderedAccessView(This,pTargetedResource,pFeedbackResource,DestDescriptor) )
+
+#define ID3D12Device13_GetCopyableFootprints1(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) \
+ ( (This)->lpVtbl -> GetCopyableFootprints1(This,pResourceDesc,FirstSubresource,NumSubresources,BaseOffset,pLayouts,pNumRows,pRowSizeInBytes,pTotalBytes) )
+
+
+#define ID3D12Device13_CreateShaderCacheSession(This,pDesc,riid,ppvSession) \
+ ( (This)->lpVtbl -> CreateShaderCacheSession(This,pDesc,riid,ppvSession) )
+
+#define ID3D12Device13_ShaderCacheControl(This,Kinds,Control) \
+ ( (This)->lpVtbl -> ShaderCacheControl(This,Kinds,Control) )
+
+#define ID3D12Device13_CreateCommandQueue1(This,pDesc,CreatorID,riid,ppCommandQueue) \
+ ( (This)->lpVtbl -> CreateCommandQueue1(This,pDesc,CreatorID,riid,ppCommandQueue) )
+
+
+#define ID3D12Device13_CreateCommittedResource3(This,pHeapProperties,HeapFlags,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riidResource,ppvResource) \
+ ( (This)->lpVtbl -> CreateCommittedResource3(This,pHeapProperties,HeapFlags,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riidResource,ppvResource) )
+
+#define ID3D12Device13_CreatePlacedResource2(This,pHeap,HeapOffset,pDesc,InitialLayout,pOptimizedClearValue,NumCastableFormats,pCastableFormats,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreatePlacedResource2(This,pHeap,HeapOffset,pDesc,InitialLayout,pOptimizedClearValue,NumCastableFormats,pCastableFormats,riid,ppvResource) )
+
+#define ID3D12Device13_CreateReservedResource2(This,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riid,ppvResource) \
+ ( (This)->lpVtbl -> CreateReservedResource2(This,pDesc,InitialLayout,pOptimizedClearValue,pProtectedSession,NumCastableFormats,pCastableFormats,riid,ppvResource) )
+
+
+#define ID3D12Device13_CreateSampler2(This,pDesc,DestDescriptor) \
+ ( (This)->lpVtbl -> CreateSampler2(This,pDesc,DestDescriptor) )
+
+#if !defined(_WIN32)
+
+#define ID3D12Device13_GetResourceAllocationInfo3(This,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo3(This,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) )
+#else
+#define ID3D12Device13_GetResourceAllocationInfo3(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) \
+ ( (This)->lpVtbl -> GetResourceAllocationInfo3(This,RetVal,visibleMask,numResourceDescs,pResourceDescs,pNumCastableFormats,ppCastableFormats,pResourceAllocationInfo1) )
+#endif
+
+
+#define ID3D12Device13_OpenExistingHeapFromAddress1(This,pAddress,size,riid,ppvHeap) \
+ ( (This)->lpVtbl -> OpenExistingHeapFromAddress1(This,pAddress,size,riid,ppvHeap) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ID3D12Device13_INTERFACE_DEFINED__ */
+
+
#ifndef __ID3D12VirtualizationGuestDevice_INTERFACE_DEFINED__
#define __ID3D12VirtualizationGuestDevice_INTERFACE_DEFINED__
@@ -24487,7 +26796,7 @@ EXTERN_C const IID IID_ID3D12Tools;
#endif /* __ID3D12Tools_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0057 */
+/* interface __MIDL_itf_d3d12_0000_0059 */
/* [local] */
typedef struct D3D12_SUBRESOURCE_DATA
@@ -24622,8 +26931,8 @@ HRESULT WINAPI D3D12GetInterface( _In_ REFCLSID rclsid, _In_ REFIID riid, _COM_O
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0057_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0057_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0059_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0059_v0_0_s_ifspec;
#ifndef __ID3D12SDKConfiguration_INTERFACE_DEFINED__
#define __ID3D12SDKConfiguration_INTERFACE_DEFINED__
@@ -24818,7 +27127,7 @@ EXTERN_C const IID IID_ID3D12SDKConfiguration1;
#endif /* __ID3D12SDKConfiguration1_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0059 */
+/* interface __MIDL_itf_d3d12_0000_0061 */
/* [local] */
typedef
@@ -24833,8 +27142,8 @@ enum D3D12_DEVICE_FACTORY_FLAGS
DEFINE_ENUM_FLAG_OPERATORS( D3D12_DEVICE_FACTORY_FLAGS );
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0059_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0059_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0061_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0061_v0_0_s_ifspec;
#ifndef __ID3D12DeviceFactory_INTERFACE_DEFINED__
#define __ID3D12DeviceFactory_INTERFACE_DEFINED__
@@ -24995,7 +27304,7 @@ EXTERN_C const IID IID_ID3D12DeviceFactory;
#endif /* __ID3D12DeviceFactory_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0060 */
+/* interface __MIDL_itf_d3d12_0000_0062 */
/* [local] */
typedef
@@ -25026,8 +27335,8 @@ typedef struct D3D12_DEVICE_CONFIGURATION_DESC
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0060_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0060_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0062_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0062_v0_0_s_ifspec;
#ifndef __ID3D12DeviceConfiguration_INTERFACE_DEFINED__
#define __ID3D12DeviceConfiguration_INTERFACE_DEFINED__
@@ -25173,7 +27482,7 @@ EXTERN_C const IID IID_ID3D12DeviceConfiguration;
#endif /* __ID3D12DeviceConfiguration_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0061 */
+/* interface __MIDL_itf_d3d12_0000_0063 */
/* [local] */
typedef
@@ -25213,8 +27522,8 @@ enum D3D12_SHADING_RATE_COMBINER
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0061_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0061_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0063_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0063_v0_0_s_ifspec;
#ifndef __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__
#define __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__
@@ -26049,7 +28358,7 @@ EXTERN_C const IID IID_ID3D12GraphicsCommandList5;
#endif /* __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0062 */
+/* interface __MIDL_itf_d3d12_0000_0064 */
/* [local] */
typedef struct D3D12_DISPATCH_MESH_ARGUMENTS
@@ -26061,8 +28370,8 @@ typedef struct D3D12_DISPATCH_MESH_ARGUMENTS
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0062_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0062_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0064_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0064_v0_0_s_ifspec;
#ifndef __ID3D12GraphicsCommandList6_INTERFACE_DEFINED__
#define __ID3D12GraphicsCommandList6_INTERFACE_DEFINED__
@@ -28618,7 +30927,891 @@ EXTERN_C const IID IID_ID3D12GraphicsCommandList8;
#endif /* __ID3D12GraphicsCommandList8_INTERFACE_DEFINED__ */
-/* interface __MIDL_itf_d3d12_0000_0065 */
+#ifndef __ID3D12GraphicsCommandList9_INTERFACE_DEFINED__
+#define __ID3D12GraphicsCommandList9_INTERFACE_DEFINED__
+
+/* interface ID3D12GraphicsCommandList9 */
+/* [unique][local][object][uuid] */
+
+
+EXTERN_C const IID IID_ID3D12GraphicsCommandList9;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("34ed2808-ffe6-4c2b-b11a-cabd2b0c59e1")
+ ID3D12GraphicsCommandList9 : public ID3D12GraphicsCommandList8
+ {
+ public:
+ virtual void STDMETHODCALLTYPE RSSetDepthBias(
+ _In_ FLOAT DepthBias,
+ _In_ FLOAT DepthBiasClamp,
+ _In_ FLOAT SlopeScaledDepthBias) = 0;
+
+ virtual void STDMETHODCALLTYPE IASetIndexBufferStripCutValue(
+ _In_ D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ID3D12GraphicsCommandList9Vtbl
+ {
+ BEGIN_INTERFACE
+
+ DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ID3D12GraphicsCommandList9 * This,
+ REFIID riid,
+ _COM_Outptr_ void **ppvObject);
+
+ DECLSPEC_XFGVIRT(IUnknown, AddRef)
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(IUnknown, Release)
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, GetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *GetPrivateData )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ REFGUID guid,
+ _Inout_ UINT *pDataSize,
+ _Out_writes_bytes_opt_( *pDataSize ) void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateData)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateData )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ REFGUID guid,
+ _In_ UINT DataSize,
+ _In_reads_bytes_opt_( DataSize ) const void *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetPrivateDataInterface)
+ HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ REFGUID guid,
+ _In_opt_ const IUnknown *pData);
+
+ DECLSPEC_XFGVIRT(ID3D12Object, SetName)
+ HRESULT ( STDMETHODCALLTYPE *SetName )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_z_ LPCWSTR Name);
+
+ DECLSPEC_XFGVIRT(ID3D12DeviceChild, GetDevice)
+ HRESULT ( STDMETHODCALLTYPE *GetDevice )(
+ ID3D12GraphicsCommandList9 * This,
+ REFIID riid,
+ _COM_Outptr_opt_ void **ppvDevice);
+
+ DECLSPEC_XFGVIRT(ID3D12CommandList, GetType)
+ D3D12_COMMAND_LIST_TYPE ( STDMETHODCALLTYPE *GetType )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, Close)
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, Reset)
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12CommandAllocator *pAllocator,
+ _In_opt_ ID3D12PipelineState *pInitialState);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ClearState)
+ void ( STDMETHODCALLTYPE *ClearState )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12PipelineState *pPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, DrawInstanced)
+ void ( STDMETHODCALLTYPE *DrawInstanced )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT VertexCountPerInstance,
+ _In_ UINT InstanceCount,
+ _In_ UINT StartVertexLocation,
+ _In_ UINT StartInstanceLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, DrawIndexedInstanced)
+ void ( STDMETHODCALLTYPE *DrawIndexedInstanced )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT IndexCountPerInstance,
+ _In_ UINT InstanceCount,
+ _In_ UINT StartIndexLocation,
+ _In_ INT BaseVertexLocation,
+ _In_ UINT StartInstanceLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, Dispatch)
+ void ( STDMETHODCALLTYPE *Dispatch )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT ThreadGroupCountX,
+ _In_ UINT ThreadGroupCountY,
+ _In_ UINT ThreadGroupCountZ);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, CopyBufferRegion)
+ void ( STDMETHODCALLTYPE *CopyBufferRegion )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstBuffer,
+ UINT64 DstOffset,
+ _In_ ID3D12Resource *pSrcBuffer,
+ UINT64 SrcOffset,
+ UINT64 NumBytes);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, CopyTextureRegion)
+ void ( STDMETHODCALLTYPE *CopyTextureRegion )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ const D3D12_TEXTURE_COPY_LOCATION *pDst,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ _In_ const D3D12_TEXTURE_COPY_LOCATION *pSrc,
+ _In_opt_ const D3D12_BOX *pSrcBox);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, CopyResource)
+ void ( STDMETHODCALLTYPE *CopyResource )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstResource,
+ _In_ ID3D12Resource *pSrcResource);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, CopyTiles)
+ void ( STDMETHODCALLTYPE *CopyTiles )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pTiledResource,
+ _In_ const D3D12_TILED_RESOURCE_COORDINATE *pTileRegionStartCoordinate,
+ _In_ const D3D12_TILE_REGION_SIZE *pTileRegionSize,
+ _In_ ID3D12Resource *pBuffer,
+ UINT64 BufferStartOffsetInBytes,
+ D3D12_TILE_COPY_FLAGS Flags);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ResolveSubresource)
+ void ( STDMETHODCALLTYPE *ResolveSubresource )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstResource,
+ _In_ UINT DstSubresource,
+ _In_ ID3D12Resource *pSrcResource,
+ _In_ UINT SrcSubresource,
+ _In_ DXGI_FORMAT Format);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, IASetPrimitiveTopology)
+ void ( STDMETHODCALLTYPE *IASetPrimitiveTopology )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, RSSetViewports)
+ void ( STDMETHODCALLTYPE *RSSetViewports )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumViewports,
+ _In_reads_( NumViewports) const D3D12_VIEWPORT *pViewports);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, RSSetScissorRects)
+ void ( STDMETHODCALLTYPE *RSSetScissorRects )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumRects,
+ _In_reads_( NumRects) const D3D12_RECT *pRects);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, OMSetBlendFactor)
+ void ( STDMETHODCALLTYPE *OMSetBlendFactor )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_reads_opt_(4) const FLOAT BlendFactor[ 4 ]);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, OMSetStencilRef)
+ void ( STDMETHODCALLTYPE *OMSetStencilRef )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT StencilRef);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetPipelineState)
+ void ( STDMETHODCALLTYPE *SetPipelineState )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12PipelineState *pPipelineState);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ResourceBarrier)
+ void ( STDMETHODCALLTYPE *ResourceBarrier )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT NumBarriers,
+ _In_reads_(NumBarriers) const D3D12_RESOURCE_BARRIER *pBarriers);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ExecuteBundle)
+ void ( STDMETHODCALLTYPE *ExecuteBundle )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12GraphicsCommandList *pCommandList);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetDescriptorHeaps)
+ void ( STDMETHODCALLTYPE *SetDescriptorHeaps )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT NumDescriptorHeaps,
+ _In_reads_(NumDescriptorHeaps) ID3D12DescriptorHeap *const *ppDescriptorHeaps);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRootSignature)
+ void ( STDMETHODCALLTYPE *SetComputeRootSignature )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12RootSignature *pRootSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRootSignature)
+ void ( STDMETHODCALLTYPE *SetGraphicsRootSignature )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12RootSignature *pRootSignature);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRootDescriptorTable)
+ void ( STDMETHODCALLTYPE *SetComputeRootDescriptorTable )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRootDescriptorTable)
+ void ( STDMETHODCALLTYPE *SetGraphicsRootDescriptorTable )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRoot32BitConstant)
+ void ( STDMETHODCALLTYPE *SetComputeRoot32BitConstant )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ UINT SrcData,
+ _In_ UINT DestOffsetIn32BitValues);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRoot32BitConstant)
+ void ( STDMETHODCALLTYPE *SetGraphicsRoot32BitConstant )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ UINT SrcData,
+ _In_ UINT DestOffsetIn32BitValues);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRoot32BitConstants)
+ void ( STDMETHODCALLTYPE *SetComputeRoot32BitConstants )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ UINT Num32BitValuesToSet,
+ _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void *pSrcData,
+ _In_ UINT DestOffsetIn32BitValues);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRoot32BitConstants)
+ void ( STDMETHODCALLTYPE *SetGraphicsRoot32BitConstants )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ UINT Num32BitValuesToSet,
+ _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void *pSrcData,
+ _In_ UINT DestOffsetIn32BitValues);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRootConstantBufferView)
+ void ( STDMETHODCALLTYPE *SetComputeRootConstantBufferView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRootConstantBufferView)
+ void ( STDMETHODCALLTYPE *SetGraphicsRootConstantBufferView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRootShaderResourceView)
+ void ( STDMETHODCALLTYPE *SetComputeRootShaderResourceView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRootShaderResourceView)
+ void ( STDMETHODCALLTYPE *SetGraphicsRootShaderResourceView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetComputeRootUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *SetComputeRootUnorderedAccessView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetGraphicsRootUnorderedAccessView)
+ void ( STDMETHODCALLTYPE *SetGraphicsRootUnorderedAccessView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT RootParameterIndex,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, IASetIndexBuffer)
+ void ( STDMETHODCALLTYPE *IASetIndexBuffer )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ const D3D12_INDEX_BUFFER_VIEW *pView);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, IASetVertexBuffers)
+ void ( STDMETHODCALLTYPE *IASetVertexBuffers )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT StartSlot,
+ _In_ UINT NumViews,
+ _In_reads_opt_(NumViews) const D3D12_VERTEX_BUFFER_VIEW *pViews);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SOSetTargets)
+ void ( STDMETHODCALLTYPE *SOSetTargets )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT StartSlot,
+ _In_ UINT NumViews,
+ _In_reads_opt_(NumViews) const D3D12_STREAM_OUTPUT_BUFFER_VIEW *pViews);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, OMSetRenderTargets)
+ void ( STDMETHODCALLTYPE *OMSetRenderTargets )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT NumRenderTargetDescriptors,
+ _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE *pRenderTargetDescriptors,
+ _In_ BOOL RTsSingleHandleToDescriptorRange,
+ _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE *pDepthStencilDescriptor);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ClearDepthStencilView)
+ void ( STDMETHODCALLTYPE *ClearDepthStencilView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView,
+ _In_ D3D12_CLEAR_FLAGS ClearFlags,
+ _In_ FLOAT Depth,
+ _In_ UINT8 Stencil,
+ _In_ UINT NumRects,
+ _In_reads_(NumRects) const D3D12_RECT *pRects);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ClearRenderTargetView)
+ void ( STDMETHODCALLTYPE *ClearRenderTargetView )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView,
+ _In_ const FLOAT ColorRGBA[ 4 ],
+ _In_ UINT NumRects,
+ _In_reads_(NumRects) const D3D12_RECT *pRects);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ClearUnorderedAccessViewUint)
+ void ( STDMETHODCALLTYPE *ClearUnorderedAccessViewUint )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle,
+ _In_ ID3D12Resource *pResource,
+ _In_ const UINT Values[ 4 ],
+ _In_ UINT NumRects,
+ _In_reads_(NumRects) const D3D12_RECT *pRects);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ClearUnorderedAccessViewFloat)
+ void ( STDMETHODCALLTYPE *ClearUnorderedAccessViewFloat )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap,
+ _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle,
+ _In_ ID3D12Resource *pResource,
+ _In_ const FLOAT Values[ 4 ],
+ _In_ UINT NumRects,
+ _In_reads_(NumRects) const D3D12_RECT *pRects);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, DiscardResource)
+ void ( STDMETHODCALLTYPE *DiscardResource )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pResource,
+ _In_opt_ const D3D12_DISCARD_REGION *pRegion);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, BeginQuery)
+ void ( STDMETHODCALLTYPE *BeginQuery )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12QueryHeap *pQueryHeap,
+ _In_ D3D12_QUERY_TYPE Type,
+ _In_ UINT Index);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, EndQuery)
+ void ( STDMETHODCALLTYPE *EndQuery )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12QueryHeap *pQueryHeap,
+ _In_ D3D12_QUERY_TYPE Type,
+ _In_ UINT Index);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ResolveQueryData)
+ void ( STDMETHODCALLTYPE *ResolveQueryData )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12QueryHeap *pQueryHeap,
+ _In_ D3D12_QUERY_TYPE Type,
+ _In_ UINT StartIndex,
+ _In_ UINT NumQueries,
+ _In_ ID3D12Resource *pDestinationBuffer,
+ _In_ UINT64 AlignedDestinationBufferOffset);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetPredication)
+ void ( STDMETHODCALLTYPE *SetPredication )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12Resource *pBuffer,
+ _In_ UINT64 AlignedBufferOffset,
+ _In_ D3D12_PREDICATION_OP Operation);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, SetMarker)
+ void ( STDMETHODCALLTYPE *SetMarker )(
+ ID3D12GraphicsCommandList9 * This,
+ UINT Metadata,
+ _In_reads_bytes_opt_(Size) const void *pData,
+ UINT Size);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, BeginEvent)
+ void ( STDMETHODCALLTYPE *BeginEvent )(
+ ID3D12GraphicsCommandList9 * This,
+ UINT Metadata,
+ _In_reads_bytes_opt_(Size) const void *pData,
+ UINT Size);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, EndEvent)
+ void ( STDMETHODCALLTYPE *EndEvent )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList, ExecuteIndirect)
+ void ( STDMETHODCALLTYPE *ExecuteIndirect )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12CommandSignature *pCommandSignature,
+ _In_ UINT MaxCommandCount,
+ _In_ ID3D12Resource *pArgumentBuffer,
+ _In_ UINT64 ArgumentBufferOffset,
+ _In_opt_ ID3D12Resource *pCountBuffer,
+ _In_ UINT64 CountBufferOffset);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, AtomicCopyBufferUINT)
+ void ( STDMETHODCALLTYPE *AtomicCopyBufferUINT )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstBuffer,
+ UINT64 DstOffset,
+ _In_ ID3D12Resource *pSrcBuffer,
+ UINT64 SrcOffset,
+ UINT Dependencies,
+ _In_reads_(Dependencies) ID3D12Resource *const *ppDependentResources,
+ _In_reads_(Dependencies) const D3D12_SUBRESOURCE_RANGE_UINT64 *pDependentSubresourceRanges);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, AtomicCopyBufferUINT64)
+ void ( STDMETHODCALLTYPE *AtomicCopyBufferUINT64 )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstBuffer,
+ UINT64 DstOffset,
+ _In_ ID3D12Resource *pSrcBuffer,
+ UINT64 SrcOffset,
+ UINT Dependencies,
+ _In_reads_(Dependencies) ID3D12Resource *const *ppDependentResources,
+ _In_reads_(Dependencies) const D3D12_SUBRESOURCE_RANGE_UINT64 *pDependentSubresourceRanges);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, OMSetDepthBounds)
+ void ( STDMETHODCALLTYPE *OMSetDepthBounds )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ FLOAT Min,
+ _In_ FLOAT Max);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, SetSamplePositions)
+ void ( STDMETHODCALLTYPE *SetSamplePositions )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT NumSamplesPerPixel,
+ _In_ UINT NumPixels,
+ _In_reads_(NumSamplesPerPixel*NumPixels) D3D12_SAMPLE_POSITION *pSamplePositions);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, ResolveSubresourceRegion)
+ void ( STDMETHODCALLTYPE *ResolveSubresourceRegion )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12Resource *pDstResource,
+ _In_ UINT DstSubresource,
+ _In_ UINT DstX,
+ _In_ UINT DstY,
+ _In_ ID3D12Resource *pSrcResource,
+ _In_ UINT SrcSubresource,
+ _In_opt_ D3D12_RECT *pSrcRect,
+ _In_ DXGI_FORMAT Format,
+ _In_ D3D12_RESOLVE_MODE ResolveMode);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList1, SetViewInstanceMask)
+ void ( STDMETHODCALLTYPE *SetViewInstanceMask )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT Mask);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList2, WriteBufferImmediate)
+ void ( STDMETHODCALLTYPE *WriteBufferImmediate )(
+ ID3D12GraphicsCommandList9 * This,
+ UINT Count,
+ _In_reads_(Count) const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *pParams,
+ _In_reads_opt_(Count) const D3D12_WRITEBUFFERIMMEDIATE_MODE *pModes);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList3, SetProtectedResourceSession)
+ void ( STDMETHODCALLTYPE *SetProtectedResourceSession )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12ProtectedResourceSession *pProtectedResourceSession);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, BeginRenderPass)
+ void ( STDMETHODCALLTYPE *BeginRenderPass )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT NumRenderTargets,
+ _In_reads_opt_(NumRenderTargets) const D3D12_RENDER_PASS_RENDER_TARGET_DESC *pRenderTargets,
+ _In_opt_ const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC *pDepthStencil,
+ D3D12_RENDER_PASS_FLAGS Flags);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, EndRenderPass)
+ void ( STDMETHODCALLTYPE *EndRenderPass )(
+ ID3D12GraphicsCommandList9 * This);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, InitializeMetaCommand)
+ void ( STDMETHODCALLTYPE *InitializeMetaCommand )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12MetaCommand *pMetaCommand,
+ _In_reads_bytes_opt_(InitializationParametersDataSizeInBytes) const void *pInitializationParametersData,
+ _In_ SIZE_T InitializationParametersDataSizeInBytes);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, ExecuteMetaCommand)
+ void ( STDMETHODCALLTYPE *ExecuteMetaCommand )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12MetaCommand *pMetaCommand,
+ _In_reads_bytes_opt_(ExecutionParametersDataSizeInBytes) const void *pExecutionParametersData,
+ _In_ SIZE_T ExecutionParametersDataSizeInBytes);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, BuildRaytracingAccelerationStructure)
+ void ( STDMETHODCALLTYPE *BuildRaytracingAccelerationStructure )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *pDesc,
+ _In_ UINT NumPostbuildInfoDescs,
+ _In_reads_opt_(NumPostbuildInfoDescs) const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *pPostbuildInfoDescs);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, EmitRaytracingAccelerationStructurePostbuildInfo)
+ void ( STDMETHODCALLTYPE *EmitRaytracingAccelerationStructurePostbuildInfo )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *pDesc,
+ _In_ UINT NumSourceAccelerationStructures,
+ _In_reads_( NumSourceAccelerationStructures ) const D3D12_GPU_VIRTUAL_ADDRESS *pSourceAccelerationStructureData);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, CopyRaytracingAccelerationStructure)
+ void ( STDMETHODCALLTYPE *CopyRaytracingAccelerationStructure )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS DestAccelerationStructureData,
+ _In_ D3D12_GPU_VIRTUAL_ADDRESS SourceAccelerationStructureData,
+ _In_ D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE Mode);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, SetPipelineState1)
+ void ( STDMETHODCALLTYPE *SetPipelineState1 )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ ID3D12StateObject *pStateObject);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList4, DispatchRays)
+ void ( STDMETHODCALLTYPE *DispatchRays )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ const D3D12_DISPATCH_RAYS_DESC *pDesc);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList5, RSSetShadingRate)
+ void ( STDMETHODCALLTYPE *RSSetShadingRate )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_SHADING_RATE baseShadingRate,
+ _In_reads_opt_(D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT) const D3D12_SHADING_RATE_COMBINER *combiners);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList5, RSSetShadingRateImage)
+ void ( STDMETHODCALLTYPE *RSSetShadingRateImage )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_opt_ ID3D12Resource *shadingRateImage);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList6, DispatchMesh)
+ void ( STDMETHODCALLTYPE *DispatchMesh )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT ThreadGroupCountX,
+ _In_ UINT ThreadGroupCountY,
+ _In_ UINT ThreadGroupCountZ);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList7, Barrier)
+ void ( STDMETHODCALLTYPE *Barrier )(
+ ID3D12GraphicsCommandList9 * This,
+ UINT32 NumBarrierGroups,
+ _In_reads_(NumBarrierGroups) const D3D12_BARRIER_GROUP *pBarrierGroups);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList8, OMSetFrontAndBackStencilRef)
+ void ( STDMETHODCALLTYPE *OMSetFrontAndBackStencilRef )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ UINT FrontStencilRef,
+ _In_ UINT BackStencilRef);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList9, RSSetDepthBias)
+ void ( STDMETHODCALLTYPE *RSSetDepthBias )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ FLOAT DepthBias,
+ _In_ FLOAT DepthBiasClamp,
+ _In_ FLOAT SlopeScaledDepthBias);
+
+ DECLSPEC_XFGVIRT(ID3D12GraphicsCommandList9, IASetIndexBufferStripCutValue)
+ void ( STDMETHODCALLTYPE *IASetIndexBufferStripCutValue )(
+ ID3D12GraphicsCommandList9 * This,
+ _In_ D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue);
+
+ END_INTERFACE
+ } ID3D12GraphicsCommandList9Vtbl;
+
+ interface ID3D12GraphicsCommandList9
+ {
+ CONST_VTBL struct ID3D12GraphicsCommandList9Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ID3D12GraphicsCommandList9_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ID3D12GraphicsCommandList9_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ID3D12GraphicsCommandList9_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ID3D12GraphicsCommandList9_GetPrivateData(This,guid,pDataSize,pData) \
+ ( (This)->lpVtbl -> GetPrivateData(This,guid,pDataSize,pData) )
+
+#define ID3D12GraphicsCommandList9_SetPrivateData(This,guid,DataSize,pData) \
+ ( (This)->lpVtbl -> SetPrivateData(This,guid,DataSize,pData) )
+
+#define ID3D12GraphicsCommandList9_SetPrivateDataInterface(This,guid,pData) \
+ ( (This)->lpVtbl -> SetPrivateDataInterface(This,guid,pData) )
+
+#define ID3D12GraphicsCommandList9_SetName(This,Name) \
+ ( (This)->lpVtbl -> SetName(This,Name) )
+
+
+#define ID3D12GraphicsCommandList9_GetDevice(This,riid,ppvDevice) \
+ ( (This)->lpVtbl -> GetDevice(This,riid,ppvDevice) )
+
+
+#define ID3D12GraphicsCommandList9_GetType(This) \
+ ( (This)->lpVtbl -> GetType(This) )
+
+
+#define ID3D12GraphicsCommandList9_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ID3D12GraphicsCommandList9_Reset(This,pAllocator,pInitialState) \
+ ( (This)->lpVtbl -> Reset(This,pAllocator,pInitialState) )
+
+#define ID3D12GraphicsCommandList9_ClearState(This,pPipelineState) \
+ ( (This)->lpVtbl -> ClearState(This,pPipelineState) )
+
+#define ID3D12GraphicsCommandList9_DrawInstanced(This,VertexCountPerInstance,InstanceCount,StartVertexLocation,StartInstanceLocation) \
+ ( (This)->lpVtbl -> DrawInstanced(This,VertexCountPerInstance,InstanceCount,StartVertexLocation,StartInstanceLocation) )
+
+#define ID3D12GraphicsCommandList9_DrawIndexedInstanced(This,IndexCountPerInstance,InstanceCount,StartIndexLocation,BaseVertexLocation,StartInstanceLocation) \
+ ( (This)->lpVtbl -> DrawIndexedInstanced(This,IndexCountPerInstance,InstanceCount,StartIndexLocation,BaseVertexLocation,StartInstanceLocation) )
+
+#define ID3D12GraphicsCommandList9_Dispatch(This,ThreadGroupCountX,ThreadGroupCountY,ThreadGroupCountZ) \
+ ( (This)->lpVtbl -> Dispatch(This,ThreadGroupCountX,ThreadGroupCountY,ThreadGroupCountZ) )
+
+#define ID3D12GraphicsCommandList9_CopyBufferRegion(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,NumBytes) \
+ ( (This)->lpVtbl -> CopyBufferRegion(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,NumBytes) )
+
+#define ID3D12GraphicsCommandList9_CopyTextureRegion(This,pDst,DstX,DstY,DstZ,pSrc,pSrcBox) \
+ ( (This)->lpVtbl -> CopyTextureRegion(This,pDst,DstX,DstY,DstZ,pSrc,pSrcBox) )
+
+#define ID3D12GraphicsCommandList9_CopyResource(This,pDstResource,pSrcResource) \
+ ( (This)->lpVtbl -> CopyResource(This,pDstResource,pSrcResource) )
+
+#define ID3D12GraphicsCommandList9_CopyTiles(This,pTiledResource,pTileRegionStartCoordinate,pTileRegionSize,pBuffer,BufferStartOffsetInBytes,Flags) \
+ ( (This)->lpVtbl -> CopyTiles(This,pTiledResource,pTileRegionStartCoordinate,pTileRegionSize,pBuffer,BufferStartOffsetInBytes,Flags) )
+
+#define ID3D12GraphicsCommandList9_ResolveSubresource(This,pDstResource,DstSubresource,pSrcResource,SrcSubresource,Format) \
+ ( (This)->lpVtbl -> ResolveSubresource(This,pDstResource,DstSubresource,pSrcResource,SrcSubresource,Format) )
+
+#define ID3D12GraphicsCommandList9_IASetPrimitiveTopology(This,PrimitiveTopology) \
+ ( (This)->lpVtbl -> IASetPrimitiveTopology(This,PrimitiveTopology) )
+
+#define ID3D12GraphicsCommandList9_RSSetViewports(This,NumViewports,pViewports) \
+ ( (This)->lpVtbl -> RSSetViewports(This,NumViewports,pViewports) )
+
+#define ID3D12GraphicsCommandList9_RSSetScissorRects(This,NumRects,pRects) \
+ ( (This)->lpVtbl -> RSSetScissorRects(This,NumRects,pRects) )
+
+#define ID3D12GraphicsCommandList9_OMSetBlendFactor(This,BlendFactor) \
+ ( (This)->lpVtbl -> OMSetBlendFactor(This,BlendFactor) )
+
+#define ID3D12GraphicsCommandList9_OMSetStencilRef(This,StencilRef) \
+ ( (This)->lpVtbl -> OMSetStencilRef(This,StencilRef) )
+
+#define ID3D12GraphicsCommandList9_SetPipelineState(This,pPipelineState) \
+ ( (This)->lpVtbl -> SetPipelineState(This,pPipelineState) )
+
+#define ID3D12GraphicsCommandList9_ResourceBarrier(This,NumBarriers,pBarriers) \
+ ( (This)->lpVtbl -> ResourceBarrier(This,NumBarriers,pBarriers) )
+
+#define ID3D12GraphicsCommandList9_ExecuteBundle(This,pCommandList) \
+ ( (This)->lpVtbl -> ExecuteBundle(This,pCommandList) )
+
+#define ID3D12GraphicsCommandList9_SetDescriptorHeaps(This,NumDescriptorHeaps,ppDescriptorHeaps) \
+ ( (This)->lpVtbl -> SetDescriptorHeaps(This,NumDescriptorHeaps,ppDescriptorHeaps) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRootSignature(This,pRootSignature) \
+ ( (This)->lpVtbl -> SetComputeRootSignature(This,pRootSignature) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRootSignature(This,pRootSignature) \
+ ( (This)->lpVtbl -> SetGraphicsRootSignature(This,pRootSignature) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRootDescriptorTable(This,RootParameterIndex,BaseDescriptor) \
+ ( (This)->lpVtbl -> SetComputeRootDescriptorTable(This,RootParameterIndex,BaseDescriptor) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRootDescriptorTable(This,RootParameterIndex,BaseDescriptor) \
+ ( (This)->lpVtbl -> SetGraphicsRootDescriptorTable(This,RootParameterIndex,BaseDescriptor) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRoot32BitConstant(This,RootParameterIndex,SrcData,DestOffsetIn32BitValues) \
+ ( (This)->lpVtbl -> SetComputeRoot32BitConstant(This,RootParameterIndex,SrcData,DestOffsetIn32BitValues) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRoot32BitConstant(This,RootParameterIndex,SrcData,DestOffsetIn32BitValues) \
+ ( (This)->lpVtbl -> SetGraphicsRoot32BitConstant(This,RootParameterIndex,SrcData,DestOffsetIn32BitValues) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRoot32BitConstants(This,RootParameterIndex,Num32BitValuesToSet,pSrcData,DestOffsetIn32BitValues) \
+ ( (This)->lpVtbl -> SetComputeRoot32BitConstants(This,RootParameterIndex,Num32BitValuesToSet,pSrcData,DestOffsetIn32BitValues) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRoot32BitConstants(This,RootParameterIndex,Num32BitValuesToSet,pSrcData,DestOffsetIn32BitValues) \
+ ( (This)->lpVtbl -> SetGraphicsRoot32BitConstants(This,RootParameterIndex,Num32BitValuesToSet,pSrcData,DestOffsetIn32BitValues) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRootConstantBufferView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetComputeRootConstantBufferView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRootConstantBufferView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetGraphicsRootConstantBufferView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRootShaderResourceView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetComputeRootShaderResourceView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRootShaderResourceView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetGraphicsRootShaderResourceView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_SetComputeRootUnorderedAccessView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetComputeRootUnorderedAccessView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_SetGraphicsRootUnorderedAccessView(This,RootParameterIndex,BufferLocation) \
+ ( (This)->lpVtbl -> SetGraphicsRootUnorderedAccessView(This,RootParameterIndex,BufferLocation) )
+
+#define ID3D12GraphicsCommandList9_IASetIndexBuffer(This,pView) \
+ ( (This)->lpVtbl -> IASetIndexBuffer(This,pView) )
+
+#define ID3D12GraphicsCommandList9_IASetVertexBuffers(This,StartSlot,NumViews,pViews) \
+ ( (This)->lpVtbl -> IASetVertexBuffers(This,StartSlot,NumViews,pViews) )
+
+#define ID3D12GraphicsCommandList9_SOSetTargets(This,StartSlot,NumViews,pViews) \
+ ( (This)->lpVtbl -> SOSetTargets(This,StartSlot,NumViews,pViews) )
+
+#define ID3D12GraphicsCommandList9_OMSetRenderTargets(This,NumRenderTargetDescriptors,pRenderTargetDescriptors,RTsSingleHandleToDescriptorRange,pDepthStencilDescriptor) \
+ ( (This)->lpVtbl -> OMSetRenderTargets(This,NumRenderTargetDescriptors,pRenderTargetDescriptors,RTsSingleHandleToDescriptorRange,pDepthStencilDescriptor) )
+
+#define ID3D12GraphicsCommandList9_ClearDepthStencilView(This,DepthStencilView,ClearFlags,Depth,Stencil,NumRects,pRects) \
+ ( (This)->lpVtbl -> ClearDepthStencilView(This,DepthStencilView,ClearFlags,Depth,Stencil,NumRects,pRects) )
+
+#define ID3D12GraphicsCommandList9_ClearRenderTargetView(This,RenderTargetView,ColorRGBA,NumRects,pRects) \
+ ( (This)->lpVtbl -> ClearRenderTargetView(This,RenderTargetView,ColorRGBA,NumRects,pRects) )
+
+#define ID3D12GraphicsCommandList9_ClearUnorderedAccessViewUint(This,ViewGPUHandleInCurrentHeap,ViewCPUHandle,pResource,Values,NumRects,pRects) \
+ ( (This)->lpVtbl -> ClearUnorderedAccessViewUint(This,ViewGPUHandleInCurrentHeap,ViewCPUHandle,pResource,Values,NumRects,pRects) )
+
+#define ID3D12GraphicsCommandList9_ClearUnorderedAccessViewFloat(This,ViewGPUHandleInCurrentHeap,ViewCPUHandle,pResource,Values,NumRects,pRects) \
+ ( (This)->lpVtbl -> ClearUnorderedAccessViewFloat(This,ViewGPUHandleInCurrentHeap,ViewCPUHandle,pResource,Values,NumRects,pRects) )
+
+#define ID3D12GraphicsCommandList9_DiscardResource(This,pResource,pRegion) \
+ ( (This)->lpVtbl -> DiscardResource(This,pResource,pRegion) )
+
+#define ID3D12GraphicsCommandList9_BeginQuery(This,pQueryHeap,Type,Index) \
+ ( (This)->lpVtbl -> BeginQuery(This,pQueryHeap,Type,Index) )
+
+#define ID3D12GraphicsCommandList9_EndQuery(This,pQueryHeap,Type,Index) \
+ ( (This)->lpVtbl -> EndQuery(This,pQueryHeap,Type,Index) )
+
+#define ID3D12GraphicsCommandList9_ResolveQueryData(This,pQueryHeap,Type,StartIndex,NumQueries,pDestinationBuffer,AlignedDestinationBufferOffset) \
+ ( (This)->lpVtbl -> ResolveQueryData(This,pQueryHeap,Type,StartIndex,NumQueries,pDestinationBuffer,AlignedDestinationBufferOffset) )
+
+#define ID3D12GraphicsCommandList9_SetPredication(This,pBuffer,AlignedBufferOffset,Operation) \
+ ( (This)->lpVtbl -> SetPredication(This,pBuffer,AlignedBufferOffset,Operation) )
+
+#define ID3D12GraphicsCommandList9_SetMarker(This,Metadata,pData,Size) \
+ ( (This)->lpVtbl -> SetMarker(This,Metadata,pData,Size) )
+
+#define ID3D12GraphicsCommandList9_BeginEvent(This,Metadata,pData,Size) \
+ ( (This)->lpVtbl -> BeginEvent(This,Metadata,pData,Size) )
+
+#define ID3D12GraphicsCommandList9_EndEvent(This) \
+ ( (This)->lpVtbl -> EndEvent(This) )
+
+#define ID3D12GraphicsCommandList9_ExecuteIndirect(This,pCommandSignature,MaxCommandCount,pArgumentBuffer,ArgumentBufferOffset,pCountBuffer,CountBufferOffset) \
+ ( (This)->lpVtbl -> ExecuteIndirect(This,pCommandSignature,MaxCommandCount,pArgumentBuffer,ArgumentBufferOffset,pCountBuffer,CountBufferOffset) )
+
+
+#define ID3D12GraphicsCommandList9_AtomicCopyBufferUINT(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,Dependencies,ppDependentResources,pDependentSubresourceRanges) \
+ ( (This)->lpVtbl -> AtomicCopyBufferUINT(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,Dependencies,ppDependentResources,pDependentSubresourceRanges) )
+
+#define ID3D12GraphicsCommandList9_AtomicCopyBufferUINT64(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,Dependencies,ppDependentResources,pDependentSubresourceRanges) \
+ ( (This)->lpVtbl -> AtomicCopyBufferUINT64(This,pDstBuffer,DstOffset,pSrcBuffer,SrcOffset,Dependencies,ppDependentResources,pDependentSubresourceRanges) )
+
+#define ID3D12GraphicsCommandList9_OMSetDepthBounds(This,Min,Max) \
+ ( (This)->lpVtbl -> OMSetDepthBounds(This,Min,Max) )
+
+#define ID3D12GraphicsCommandList9_SetSamplePositions(This,NumSamplesPerPixel,NumPixels,pSamplePositions) \
+ ( (This)->lpVtbl -> SetSamplePositions(This,NumSamplesPerPixel,NumPixels,pSamplePositions) )
+
+#define ID3D12GraphicsCommandList9_ResolveSubresourceRegion(This,pDstResource,DstSubresource,DstX,DstY,pSrcResource,SrcSubresource,pSrcRect,Format,ResolveMode) \
+ ( (This)->lpVtbl -> ResolveSubresourceRegion(This,pDstResource,DstSubresource,DstX,DstY,pSrcResource,SrcSubresource,pSrcRect,Format,ResolveMode) )
+
+#define ID3D12GraphicsCommandList9_SetViewInstanceMask(This,Mask) \
+ ( (This)->lpVtbl -> SetViewInstanceMask(This,Mask) )
+
+
+#define ID3D12GraphicsCommandList9_WriteBufferImmediate(This,Count,pParams,pModes) \
+ ( (This)->lpVtbl -> WriteBufferImmediate(This,Count,pParams,pModes) )
+
+
+#define ID3D12GraphicsCommandList9_SetProtectedResourceSession(This,pProtectedResourceSession) \
+ ( (This)->lpVtbl -> SetProtectedResourceSession(This,pProtectedResourceSession) )
+
+
+#define ID3D12GraphicsCommandList9_BeginRenderPass(This,NumRenderTargets,pRenderTargets,pDepthStencil,Flags) \
+ ( (This)->lpVtbl -> BeginRenderPass(This,NumRenderTargets,pRenderTargets,pDepthStencil,Flags) )
+
+#define ID3D12GraphicsCommandList9_EndRenderPass(This) \
+ ( (This)->lpVtbl -> EndRenderPass(This) )
+
+#define ID3D12GraphicsCommandList9_InitializeMetaCommand(This,pMetaCommand,pInitializationParametersData,InitializationParametersDataSizeInBytes) \
+ ( (This)->lpVtbl -> InitializeMetaCommand(This,pMetaCommand,pInitializationParametersData,InitializationParametersDataSizeInBytes) )
+
+#define ID3D12GraphicsCommandList9_ExecuteMetaCommand(This,pMetaCommand,pExecutionParametersData,ExecutionParametersDataSizeInBytes) \
+ ( (This)->lpVtbl -> ExecuteMetaCommand(This,pMetaCommand,pExecutionParametersData,ExecutionParametersDataSizeInBytes) )
+
+#define ID3D12GraphicsCommandList9_BuildRaytracingAccelerationStructure(This,pDesc,NumPostbuildInfoDescs,pPostbuildInfoDescs) \
+ ( (This)->lpVtbl -> BuildRaytracingAccelerationStructure(This,pDesc,NumPostbuildInfoDescs,pPostbuildInfoDescs) )
+
+#define ID3D12GraphicsCommandList9_EmitRaytracingAccelerationStructurePostbuildInfo(This,pDesc,NumSourceAccelerationStructures,pSourceAccelerationStructureData) \
+ ( (This)->lpVtbl -> EmitRaytracingAccelerationStructurePostbuildInfo(This,pDesc,NumSourceAccelerationStructures,pSourceAccelerationStructureData) )
+
+#define ID3D12GraphicsCommandList9_CopyRaytracingAccelerationStructure(This,DestAccelerationStructureData,SourceAccelerationStructureData,Mode) \
+ ( (This)->lpVtbl -> CopyRaytracingAccelerationStructure(This,DestAccelerationStructureData,SourceAccelerationStructureData,Mode) )
+
+#define ID3D12GraphicsCommandList9_SetPipelineState1(This,pStateObject) \
+ ( (This)->lpVtbl -> SetPipelineState1(This,pStateObject) )
+
+#define ID3D12GraphicsCommandList9_DispatchRays(This,pDesc) \
+ ( (This)->lpVtbl -> DispatchRays(This,pDesc) )
+
+
+#define ID3D12GraphicsCommandList9_RSSetShadingRate(This,baseShadingRate,combiners) \
+ ( (This)->lpVtbl -> RSSetShadingRate(This,baseShadingRate,combiners) )
+
+#define ID3D12GraphicsCommandList9_RSSetShadingRateImage(This,shadingRateImage) \
+ ( (This)->lpVtbl -> RSSetShadingRateImage(This,shadingRateImage) )
+
+
+#define ID3D12GraphicsCommandList9_DispatchMesh(This,ThreadGroupCountX,ThreadGroupCountY,ThreadGroupCountZ) \
+ ( (This)->lpVtbl -> DispatchMesh(This,ThreadGroupCountX,ThreadGroupCountY,ThreadGroupCountZ) )
+
+
+#define ID3D12GraphicsCommandList9_Barrier(This,NumBarrierGroups,pBarrierGroups) \
+ ( (This)->lpVtbl -> Barrier(This,NumBarrierGroups,pBarrierGroups) )
+
+
+#define ID3D12GraphicsCommandList9_OMSetFrontAndBackStencilRef(This,FrontStencilRef,BackStencilRef) \
+ ( (This)->lpVtbl -> OMSetFrontAndBackStencilRef(This,FrontStencilRef,BackStencilRef) )
+
+
+#define ID3D12GraphicsCommandList9_RSSetDepthBias(This,DepthBias,DepthBiasClamp,SlopeScaledDepthBias) \
+ ( (This)->lpVtbl -> RSSetDepthBias(This,DepthBias,DepthBiasClamp,SlopeScaledDepthBias) )
+
+#define ID3D12GraphicsCommandList9_IASetIndexBufferStripCutValue(This,IBStripCutValue) \
+ ( (This)->lpVtbl -> IASetIndexBufferStripCutValue(This,IBStripCutValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ID3D12GraphicsCommandList9_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_d3d12_0000_0068 */
/* [local] */
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_GAMES) */
@@ -28678,6 +31871,8 @@ DEFINE_GUID(IID_ID3D12ShaderCacheSession,0x28e2495d,0x0f64,0x4ae4,0xa6,0xec,0x12
DEFINE_GUID(IID_ID3D12Device9,0x4c80e962,0xf032,0x4f60,0xbc,0x9e,0xeb,0xc2,0xcf,0xa1,0xd8,0x3c);
DEFINE_GUID(IID_ID3D12Device10,0x517f8718,0xaa66,0x49f9,0xb0,0x2b,0xa7,0xab,0x89,0xc0,0x60,0x31);
DEFINE_GUID(IID_ID3D12Device11,0x5405c344,0xd457,0x444e,0xb4,0xdd,0x23,0x66,0xe4,0x5a,0xee,0x39);
+DEFINE_GUID(IID_ID3D12Device12,0x5af5c532,0x4c91,0x4cd0,0xb5,0x41,0x15,0xa4,0x05,0x39,0x5f,0xc5);
+DEFINE_GUID(IID_ID3D12Device13,0x14eecffc,0x4df8,0x40f7,0xa1,0x18,0x5c,0x81,0x6f,0x45,0x69,0x5e);
DEFINE_GUID(IID_ID3D12VirtualizationGuestDevice,0xbc66d368,0x7373,0x4943,0x87,0x57,0xfc,0x87,0xdc,0x79,0xe4,0x76);
DEFINE_GUID(IID_ID3D12Tools,0x7071e1f0,0xe84b,0x4b33,0x97,0x4f,0x12,0xfa,0x49,0xde,0x65,0xc5);
DEFINE_GUID(IID_ID3D12SDKConfiguration,0xe9eb5314,0x33aa,0x42b2,0xa7,0x18,0xd7,0x7f,0x58,0xb1,0xf1,0xc7);
@@ -28688,10 +31883,11 @@ DEFINE_GUID(IID_ID3D12GraphicsCommandList5,0x55050859,0x4024,0x474c,0x87,0xf5,0x
DEFINE_GUID(IID_ID3D12GraphicsCommandList6,0xc3827890,0xe548,0x4cfa,0x96,0xcf,0x56,0x89,0xa9,0x37,0x0f,0x80);
DEFINE_GUID(IID_ID3D12GraphicsCommandList7,0xdd171223,0x8b61,0x4769,0x90,0xe3,0x16,0x0c,0xcd,0xe4,0xe2,0xc1);
DEFINE_GUID(IID_ID3D12GraphicsCommandList8,0xee936ef9,0x599d,0x4d28,0x93,0x8e,0x23,0xc4,0xad,0x05,0xce,0x51);
+DEFINE_GUID(IID_ID3D12GraphicsCommandList9,0x34ed2808,0xffe6,0x4c2b,0xb1,0x1a,0xca,0xbd,0x2b,0x0c,0x59,0xe1);
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0065_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0065_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0068_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_d3d12_0000_0068_v0_0_s_ifspec;
/* Additional Prototypes for ALL interfaces */
diff --git a/thirdparty/directx_headers/d3d12compatibility.h b/thirdparty/directx_headers/include/directx/d3d12compatibility.h
index 1a9430e5c9..1a9430e5c9 100644
--- a/thirdparty/directx_headers/d3d12compatibility.h
+++ b/thirdparty/directx_headers/include/directx/d3d12compatibility.h
diff --git a/thirdparty/directx_headers/d3d12sdklayers.h b/thirdparty/directx_headers/include/directx/d3d12sdklayers.h
index b25a8f6e5d..06aa091b55 100644
--- a/thirdparty/directx_headers/d3d12sdklayers.h
+++ b/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 */
diff --git a/thirdparty/directx_headers/d3d12shader.h b/thirdparty/directx_headers/include/directx/d3d12shader.h
index 0acf584e32..0acf584e32 100644
--- a/thirdparty/directx_headers/d3d12shader.h
+++ b/thirdparty/directx_headers/include/directx/d3d12shader.h
diff --git a/thirdparty/directx_headers/d3d12video.h b/thirdparty/directx_headers/include/directx/d3d12video.h
index add372e381..fe9a17377c 100644
--- a/thirdparty/directx_headers/d3d12video.h
+++ b/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);
@@ -6320,6 +6332,463 @@ DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2, 0x0c5f2aa1, 0xe541, 0x4089,
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
{
D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_ABSOLUTE_QP_MAP = 0,
@@ -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
@@ -6605,6 +7138,58 @@ typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE
} 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
{
D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE = 0
@@ -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;
diff --git a/thirdparty/directx_headers/d3dcommon.h b/thirdparty/directx_headers/include/directx/d3dcommon.h
index 33e7762374..974f205a60 100644
--- a/thirdparty/directx_headers/d3dcommon.h
+++ b/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,
diff --git a/thirdparty/directx_headers/include/directx/d3dx12.h b/thirdparty/directx_headers/include/directx/d3dx12.h
new file mode 100644
index 0000000000..1187816c1e
--- /dev/null
+++ b/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__
+
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_barriers.h b/thirdparty/directx_headers/include/directx/d3dx12_barriers.h
new file mode 100644
index 0000000000..2c2b135a62
--- /dev/null
+++ b/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__
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_check_feature_support.h b/thirdparty/directx_headers/include/directx/d3dx12_check_feature_support.h
new file mode 100644
index 0000000000..653a422d03
--- /dev/null
+++ b/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
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_core.h b/thirdparty/directx_headers/include/directx/d3dx12_core.h
new file mode 100644
index 0000000000..593f7637a3
--- /dev/null
+++ b/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)
+ }
+}; \ No newline at end of file
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_default.h b/thirdparty/directx_headers/include/directx/d3dx12_default.h
new file mode 100644
index 0000000000..2b74d70f77
--- /dev/null
+++ b/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;
+
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_pipeline_state_stream.h b/thirdparty/directx_headers/include/directx/d3dx12_pipeline_state_stream.h
new file mode 100644
index 0000000000..b94073d38c
--- /dev/null
+++ b/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;
+}
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_property_format_table.h b/thirdparty/directx_headers/include/directx/d3dx12_property_format_table.h
new file mode 100644
index 0000000000..301100c034
--- /dev/null
+++ b/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 \ No newline at end of file
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_render_pass.h b/thirdparty/directx_headers/include/directx/d3dx12_render_pass.h
new file mode 100644
index 0000000000..fc032f86cd
--- /dev/null
+++ b/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;
+}
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_resource_helpers.h b/thirdparty/directx_headers/include/directx/d3dx12_resource_helpers.h
new file mode 100644
index 0000000000..902ec0cd6e
--- /dev/null
+++ b/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
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h b/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h
new file mode 100644
index 0000000000..572efed852
--- /dev/null
+++ b/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;
+}
diff --git a/thirdparty/directx_headers/include/directx/d3dx12_state_object.h b/thirdparty/directx_headers/include/directx/d3dx12_state_object.h
new file mode 100644
index 0000000000..74dc6ca2d9
--- /dev/null
+++ b/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
diff --git a/thirdparty/directx_headers/dxcore.h b/thirdparty/directx_headers/include/directx/dxcore.h
index 4244eaa60f..4244eaa60f 100644
--- a/thirdparty/directx_headers/dxcore.h
+++ b/thirdparty/directx_headers/include/directx/dxcore.h
diff --git a/thirdparty/directx_headers/dxcore_interface.h b/thirdparty/directx_headers/include/directx/dxcore_interface.h
index b487fe13fb..b487fe13fb 100644
--- a/thirdparty/directx_headers/dxcore_interface.h
+++ b/thirdparty/directx_headers/include/directx/dxcore_interface.h
diff --git a/thirdparty/directx_headers/dxgicommon.h b/thirdparty/directx_headers/include/directx/dxgicommon.h
index f83aa01e61..f83aa01e61 100644
--- a/thirdparty/directx_headers/dxgicommon.h
+++ b/thirdparty/directx_headers/include/directx/dxgicommon.h
diff --git a/thirdparty/directx_headers/dxgiformat.h b/thirdparty/directx_headers/include/directx/dxgiformat.h
index 52aae1b2be..83e6c07756 100644
--- a/thirdparty/directx_headers/dxgiformat.h
+++ b/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;
diff --git a/thirdparty/directx_headers/include/dxguids/dxguids.h b/thirdparty/directx_headers/include/dxguids/dxguids.h
new file mode 100644
index 0000000000..b9a7b08fa7
--- /dev/null
+++ b/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