diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 80964074308..56e041be1b9 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 @@ -1476,6 +1476,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/templates/paged_allocator.h b/core/templates/paged_allocator.h index 72425a8c3d7..6f3f78d4d2a 100644 --- a/core/templates/paged_allocator.h +++ b/core/templates/paged_allocator.h @@ -58,7 +58,7 @@ public: }; template - T *alloc(const Args &&...p_args) { + T *alloc(Args &&...p_args) { if (thread_safe) { spin_lock.lock(); } @@ -99,6 +99,10 @@ public: } } + template + T *new_allocation(Args &&...p_args) { return alloc(p_args...); } + void delete_allocation(T *p_mem) { free(p_mem); } + private: void _reset(bool p_allow_unfreed) { if (!p_allow_unfreed || !std::is_trivially_destructible::value) { diff --git a/core/templates/rb_map.h b/core/templates/rb_map.h index d3737136691..152fddd0118 100644 --- a/core/templates/rb_map.h +++ b/core/templates/rb_map.h @@ -111,11 +111,16 @@ public: return *this; } - _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } - _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + _FORCE_INLINE_ bool operator==(const Iterator &p_it) const { return E == p_it.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &p_it) const { return E != p_it.E; } explicit operator bool() const { return E != nullptr; } + + Iterator &operator=(const Iterator &p_it) { + E = p_it.E; + return *this; + } Iterator(Element *p_E) { E = p_E; } Iterator() {} Iterator(const Iterator &p_it) { E = p_it.E; } @@ -138,11 +143,16 @@ public: return *this; } - _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; } - _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; } + _FORCE_INLINE_ bool operator==(const ConstIterator &p_it) const { return E == p_it.E; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &p_it) const { return E != p_it.E; } explicit operator bool() const { return E != nullptr; } + + ConstIterator &operator=(const ConstIterator &p_it) { + E = p_it.E; + return *this; + } ConstIterator(const Element *p_E) { E = p_E; } ConstIterator() {} ConstIterator(const ConstIterator &p_it) { E = p_it.E; } diff --git a/core/typedefs.h b/core/typedefs.h index 24c247fd388..803b2e5ae0c 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/core/variant/type_info.h b/core/variant/type_info.h index e89658d25bd..c1f2f86a963 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -287,14 +287,17 @@ class BitField { int64_t value = 0; public: - _FORCE_INLINE_ void set_flag(T p_flag) { value |= (int64_t)p_flag; } + _FORCE_INLINE_ BitField &set_flag(T p_flag) { + value |= (int64_t)p_flag; + return *this; + } _FORCE_INLINE_ bool has_flag(T p_flag) const { return value & (int64_t)p_flag; } _FORCE_INLINE_ bool is_empty() const { return value == 0; } _FORCE_INLINE_ void clear_flag(T p_flag) { value &= ~(int64_t)p_flag; } _FORCE_INLINE_ void clear() { value = 0; } - _FORCE_INLINE_ BitField() = default; - _FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; } - _FORCE_INLINE_ BitField(T p_value) { value = (int64_t)p_value; } + _FORCE_INLINE_ constexpr BitField() = default; + _FORCE_INLINE_ constexpr BitField(int64_t p_value) { value = p_value; } + _FORCE_INLINE_ constexpr BitField(T p_value) { value = (int64_t)p_value; } _FORCE_INLINE_ operator int64_t() const { return value; } _FORCE_INLINE_ operator Variant() const { return value; } }; diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 20faa702267..a841453ba0c 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -796,12 +796,13 @@ Returns the data format used to create this texture. - + 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. @@ -928,44 +929,91 @@ Represents the size of the [enum DeviceType] enum. - - Vulkan device driver resource. This is a "global" resource and ignores the RID passed in + + Specific device object based on a physical device. + - Vulkan: Vulkan device driver resource ([code]VkDevice[/code]). ([code]rid[/code] argument doesn't apply.) - - Physical device (graphics card) driver resource. + + Physical device the specific logical device is based on. + - Vulkan: [code]VkDevice[/code]. ([code]rid[/code] argument doesn't apply.) - - Vulkan instance driver resource. + + Top-most graphics API entry object. + - Vulkan: [code]VkInstance[/code]. ([code]rid[/code] argument doesn't apply.) - - Vulkan queue driver resource. + + The main graphics-compute command queue. + - Vulkan: [code]VkQueue[/code]. ([code]rid[/code] argument doesn't apply.) - - Vulkan queue family index driver resource. + + 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.) - - Vulkan image driver resource. + + - Vulkan: [code]VkImage[/code]. - - Vulkan image view driver resource. + + The view of an owned or shared texture. + - Vulkan: [code]VkImageView[/code]. - - Vulkan image native texture format driver resource. + + The native id of the data format of the texture. + - Vulkan: [code]VkFormat[/code]. - - Vulkan sampler driver resource. + + - Vulkan: [code]VkSampler[/code]. - - Vulkan [url=https://vkguide.dev/docs/chapter-4/descriptors/]descriptor set[/url] driver resource. + + - Vulkan: [code]VkDescriptorSet[/code]. - - Vulkan buffer driver resource. + + Buffer of any kind of (storage, vertex, etc.). + - Vulkan: [code]VkBuffer[/code]. - - Vulkan compute pipeline driver resource. + + - Vulkan: [code]VkPipeline[/code]. - - Vulkan render pipeline driver resource. + + - Vulkan: [code]VkPipeline[/code]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_LOGICAL_DEVICE]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_PHYSICAL_DEVICE]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TOPMOST_OBJECT]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_COMMAND_QUEUE]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_QUEUE_FAMILY]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE_VIEW]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_TEXTURE_DATA_FORMAT]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_SAMPLER]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_UNIFORM_SET]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_BUFFER]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_COMPUTE_PIPELINE]. + + + [i]Deprecated.[/i] Use [constant DRIVER_RESOURCE_RENDER_PIPELINE]. 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 ce7134fb77d..11ae52fd409 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 69330892080..36492b198b1 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 + +#include +#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 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 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 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 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(); - md.device->CreateRenderTargetView(window->render_targets[i].Get(), nullptr, rtv_handle); - rtv_handle.Offset(1, md.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV)); + 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, 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 &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 &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 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 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 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 31e75affd03..ec4bc832b65 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 -#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED -#include "D3D12MemAlloc.h" #include + +#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 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 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 rtv_heap; + RenderingDeviceDriverD3D12::RenderPassInfo render_pass; + RenderingDeviceDriverD3D12::FramebufferInfo framebuffers[IMAGE_COUNT]; }; struct LocalDevice : public DeviceBasics { @@ -161,8 +170,8 @@ private: // Commands. - Vector command_list_queue; - int command_list_count = 1; + LocalVector 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 get_device(); - ComPtr 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); + ID3D12Device *get_device(); + IDXGIAdapter *get_adapter(); + virtual int get_swapchain_image_count() const override final; - RID local_device_create(); - ComPtr 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); + 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(); + 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; - 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 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; - void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode); - DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const; + 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; + + 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 0ac2f710745..571ec952e75 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 839bcf6bc70..00000000000 --- 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(); - } - - dependency_map[p_depends_on].insert(p_id); - - if (!reverse_dependency_map.has(p_id)) { - reverse_dependency_map[p_id] = HashSet(); - } - - reverse_dependency_map[p_id].insert(p_depends_on); -} - -void RenderingDeviceD3D12::_free_dependencies(RID p_id) { - // Direct dependencies must be freed. - - HashMap>::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>::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 &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> &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 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 device10; - device.As(&device10); - bool relaxed_casting_available = device10.Get() && context->get_format_capabilities().relaxed_casting_supported; - LocalVector castable_formats; - - HashMap 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 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 &p_data, BitField 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 &p_data, BitField 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(©_dst, x, y, z, ©_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 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 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(), "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 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()); - - ERR_FAIL_COND_V_MSG(tex->bound, Vector(), - "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(), - "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()); - - 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()); - - 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(©_dst, 0, 0, 0, ©_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(), "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(©_dst, 0, 0, 0, ©_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(), "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(©_dst, 0, 0, 0, ©_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(), "Map failed with error " + vformat("0x%08ux", res) + "."); - - Vector 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 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 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 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 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 &attachments = p_fb_format->attachments; - - LocalVector 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 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 &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 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 &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 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 &p_attachments, const Vector &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::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 &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 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 &p_texture_attachments, const Vector &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { - _THREAD_SAFE_METHOD_ - - Vector attachments; - attachments.resize(p_texture_attachments.size()); - Vector 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 &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 &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 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 = ) in` to `TEXCOORD`. - 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 &p_src_buffers, const Vector &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 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 &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> &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 &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 &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 RenderingDeviceD3D12::shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name) { - SpirvReflectionData spirv_data; - if (_reflect_spirv(p_spirv, spirv_data) != OK) { - return Vector(); - } - - // Collect reflection data into binary data. - RenderingDeviceD3D12ShaderBinaryData binary_data = {}; - Vector> uniform_info; - Vector 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 &spirv_set : spirv_data.uniforms) { - Vector 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> dxil_blobs; - BitField stages_processed; - { - HashMap stages_nir_shaders; - - auto free_nir_shaders = [&]() { - for (KeyValue &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(), "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> &uniform_info; - Vector &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(), "Shader translation at stage " + String(shader_stage_names[stage]) + " failed."); - } - - Vector 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 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 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> &E : dxil_blobs) { - ShaderStage stage = E.key; - Vector &dxil_blob = E.value; - bool sign_ok = _shader_sign_dxil_bytecode(stage, dxil_blob); - ERR_FAIL_COND_V(!sign_ok, Vector()); - } - - // Build the root signature. - ComPtr 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 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 ranges; - Vector root_sig_locations; - }; - Vector resource_tables_maps; - Vector 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 &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 &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 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(), - "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> compressed_stages; - Vector zstd_size; - - uint32_t stages_binary_size = 0; - - for (int i = 0; i < p_spirv.size(); i++) { - Vector zstd; - Vector &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 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()); - } - - return ret; -} - -RID RenderingDeviceD3D12::shader_create_from_bytecode(const Vector &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(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 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(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 specialization_constants; - - for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) { - const RenderingDeviceD3D12ShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast(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> 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 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 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 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::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 &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 &p_data, BitField 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 &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 &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 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 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 attachable_textures; - struct RIDState { - bool is_buffer = false; - uint64_t shader_uniform_idx_mask = 0; - ResourceState state; - }; - HashMap 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 &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 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 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 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 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(), "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(), - "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()); - - 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(), "Map failed with error " + vformat("0x%08ux", res) + "."); - - Vector 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 &p_specialization_constants, - HashMap> &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> &E : r_final_stages_bytecode) { - ShaderStage stage = E.key; - if ((stages_re_sign_mask & (1 << stage))) { - Vector &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 &p_blob, - const Shader *p_shader, - const Vector &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 hash_bin = hc.finish(); - String hash_str = String::hex_encode_buffer(hash_bin.ptr(), hash_bin.size()); - } else { - id = p_forced_id; - } - - Vector 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 &p_specialization_constants) { - ComPtr pso_blob; - p_pso->GetCachedBlob(pso_blob.GetAddressOf()); - Vector 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 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> &p_stages_bytecode, - const Shader *p_shader, - const RID p_shader_rid, - const Vector &p_specialization_constants) { - for (const KeyValue> &E : p_stages_bytecode) { - ShaderStage stage = E.key; - const Vector &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 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 p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector &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()); - } - 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> 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> &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 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> 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 &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> 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 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> 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 screen_attachment; - screen_attachment.push_back(attachment); - return const_cast(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 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()); - - 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 &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 &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, ®ion_rect, true); - SetupInfo setup_depth(p_initial_depth_action, ®ion_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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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(&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 &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(&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 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 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 p_from, BitField 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 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 -void RenderingDeviceD3D12::_free_rids(T &p_owner, const char *p_type) { - List 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 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::Element *E = owned.front(); E;) { - List::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 &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 92ae2f78fbb..00000000000 --- 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 - -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 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 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 device; - - HashMap> dependency_map; // IDs to IDs that depend on it. - HashMap> 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 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 res_barriers_requests; - - LocalVector 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 allowed_shared_formats; - TightLocalVector 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_owner; - uint32_t texture_upload_region_size_px = 0; - - Vector _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 &p_data, BitField p_post_barrier, ID3D12GraphicsCommandList *p_command_list); - - /*****************/ - /**** SAMPLER ****/ - /*****************/ - - RID_Owner 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 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 attachments; - Vector passes; - Vector 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 framebuffer_formats; - - struct Framebuffer { - DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID; - FramebufferFormatID format_id = 0; - Vector texture_ids; // Empty if for screen. - InvalidationCallback invalidated_callback = nullptr; - void *invalidated_callback_userdata = nullptr; - Vector 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_owner; - - /***********************/ - /**** VERTEX BUFFER ****/ - /***********************/ - - RID_Owner vertex_buffer_owner; - - struct VertexDescriptionKey { - Vector 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 vertex_format_cache; - - struct VertexDescriptionCache { - Vector vertex_formats; - Vector elements_desc; - }; - - HashMap vertex_formats; - - struct VertexArray { - Vector unique_buffers; - VertexFormatID description = 0; - int vertex_count = 0; - uint32_t max_instances_allowed = 0; - Vector views; - }; - - RID_Owner 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 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 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 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 uniform_set_format_cache; - Vector::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 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 sets; - Vector set_formats; - Vector specialization_constants; - uint32_t spirv_specialization_constants_ids_mask = 0; - HashMap> stages_bytecode; - String name; // Used for debug. - - ComPtr root_signature; - ComPtr 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_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> &r_stages_bytecodes, - bool p_is_first_patch); - bool _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector &r_dxil_blob); - - /******************/ - /**** UNIFORMS ****/ - /******************/ - - RID_Owner uniform_buffer_owner; - RID_Owner storage_buffer_owner; - - // Texture buffer needs a view. - struct TextureBuffer { - Buffer buffer; - }; - - RID_Owner 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 resources; - LocalVector samplers; - } root_tables; - int uses = 0; - } recent_binds[4]; // A better amount may be empirically found. - - LocalVector attachable_textures; // Used for validation. - Vector 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 _resources_desc_info; - const Shader *_shader = nullptr; -#endif - }; - - RID_Owner uniform_set_owner; - - void _bind_uniform_set(UniformSet *p_uniform_set, const Shader::Set &p_shader_set, const Vector &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 &p_specialization_constants, - HashMap> &r_final_stages_bytecode); -#ifdef DEV_ENABLED - String _build_pipeline_blob_filename( - const Vector &p_blob, - const Shader *p_shader, - const Vector &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 &p_specialization_constants); - void _save_stages_bytecode( - const HashMap> &p_stages_bytecode, - const Shader *p_shader, - const RID p_shader_rid, - const Vector &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 set_formats; - uint32_t bindings_id = 0; - ComPtr 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>> pipeline_bindings; - uint32_t next_pipeline_binding_id = 1; - - RID_Owner render_pipeline_owner; - - struct ComputePipeline { - RID shader; - Vector set_formats; - uint32_t bindings_id = 0; - ComPtr 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 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 command_lists; // One for each frame. - }; - - Vector 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 *_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 set_formats; - Vector set_bound; - Vector 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 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 &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 &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 *_pipeline_expected_format = nullptr; - const UniformSet *_uniform_set = nullptr; -#endif - }; - - struct State { - HashSet 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 set_formats; - Vector set_bound; - Vector 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 buffers_to_dispose_of; - List textures_to_dispose_of; - List framebuffers_to_dispose_of; - List shaders_to_dispose_of; - List render_pipelines_to_dispose_of; - List 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 setup_command_allocator; - ComPtr draw_command_allocator; - ComPtr setup_command_list; // Used at the beginning of every frame for set-up. - ComPtr draw_command_list; - - struct Timestamp { - String description; - uint64_t value = 0; - }; - - ComPtr timestamp_heap; - - TightLocalVector timestamp_names; - TightLocalVector timestamp_cpu_values; - uint32_t timestamp_count = 0; - TightLocalVector timestamp_result_names; - TightLocalVector timestamp_cpu_result_values; - Buffer timestamp_result_values_buffer; - TightLocalVector 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 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> 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 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 - void _free_rids(T &p_owner, const char *p_type); - - void _finalize_command_bufers(); - void _begin_frame(); - -#ifdef DEV_ENABLED - HashMap resource_names; -#endif - - HashMap 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> &p_data = Vector>()); - 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 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 &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Vector texture_get_data(RID p_texture, uint32_t p_layer); - - virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - - /*********************/ - /**** FRAMEBUFFER ****/ - /*********************/ - - virtual FramebufferFormatID framebuffer_format_create(const Vector &p_format, uint32_t p_view_count = 1); - virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector &p_attachments, const Vector &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 &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); - virtual RID framebuffer_create_multipass(const Vector &p_texture_attachments, const Vector &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 &p_data = Vector(), 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 &p_vertex_formats); - virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector &p_src_buffers, const Vector &p_offsets = Vector()); - - virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector &p_data = Vector(), 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 shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name = ""); - - virtual RID shader_create_from_bytecode(const Vector &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 &p_data = Vector()); - virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector &p_data = Vector(), BitField p_usage = 0); - virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector &p_data = Vector()); - - virtual RID uniform_set_create(const Vector &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 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Vector 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 p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector &p_specialization_constants = Vector()); - virtual bool render_pipeline_is_valid(RID p_pipeline); - - /**************************/ - /**** COMPUTE PIPELINE ****/ - /**************************/ - - virtual RID compute_pipeline_create(RID p_shader, const Vector &p_specialization_constants = Vector()); - 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); - 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); - - 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - - virtual void barrier(BitField p_from = BARRIER_MASK_ALL_BARRIERS, BitField 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 00000000000..6a2a3c32b06 --- /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 + +#include +#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 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 &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 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 buffer; + ComPtr 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(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 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 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 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 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 main_texture; + ComPtr 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; + 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(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> &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(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> &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(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 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 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 p_vertex_attribs) { + VertexFormatInfo *vf_info = VersatileResource::allocate(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 p_src_stages, + BitField p_dst_stages, + VectorView p_memory_barriers, + VectorView p_buffer_barriers, + VectorView 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 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(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 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 p_attachments, uint32_t p_width, uint32_t p_height) { + // Pre-bookkeep. + FramebufferInfo *fb_info = VersatileResource::allocate(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> &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 &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 p_specialization_constants, + HashMap> &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> &E : r_final_stages_bytecode) { + ShaderStage stage = E.key; + if ((stages_re_sign_mask & (1 << stage))) { + Vector &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 &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 RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(VectorView p_spirv, const String &p_shader_name) { + ShaderReflection shader_refl; + if (_reflect_spirv(p_spirv, shader_refl) != OK) { + return Vector(); + } + + // Collect reflection data into binary data. + ShaderBinary::Data binary_data; + Vector> sets_bindings; + Vector 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 &spirv_set : shader_refl.uniform_sets) { + Vector 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> dxil_blobs; + BitField stages_processed; + { + HashMap stages_nir_shaders; + + auto free_nir_shaders = [&]() { + for (KeyValue &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(), "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> &sets_bindings; + Vector &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(), "Shader translation at stage " + String(SHADER_STAGE_NAMES[stage]) + " failed."); + } + + Vector 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 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 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> &E : dxil_blobs) { + ShaderStage stage = E.key; + Vector &dxil_blob = E.value; + bool sign_ok = _shader_sign_dxil_bytecode(stage, dxil_blob); + ERR_FAIL_COND_V(!sign_ok, Vector()); + } + + // Build the root signature. + ComPtr 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 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 ranges; + Vector root_sig_locations; + }; + Vector resource_tables_maps; + Vector 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 &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 &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 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(), + "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> compressed_stages; + Vector zstd_size; + + uint32_t stages_binary_size = 0; + + for (uint32_t i = 0; i < p_spirv.size(); i++) { + Vector zstd; + Vector &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 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()); + } + + return ret; +} + +RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_bytecode(const Vector &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(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(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(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 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 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(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 p_uniforms, ShaderID p_shader, uint32_t p_set_index) { + // Pre-bookkeep. + UniformSetInfo *uniform_set_info = VersatileResource::allocate(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 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 &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 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 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 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( + ©_dst, + p_regions[i].texture_offset.x, + p_regions[i].texture_offset.y, + p_regions[i].texture_offset.z, + ©_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 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(©_dst, 0, 0, 0, ©_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 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 &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 RenderingDeviceDriverD3D12::pipeline_cache_serialize() { + ERR_FAIL_V_MSG(Vector(), "Not implemented."); +} + +/*******************/ +/**** RENDERING ****/ +/*******************/ + +// ----- SUBPASS ----- + +RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView p_attachments, VectorView p_subpasses, VectorView p_subpass_dependencies, uint32_t p_view_count) { + // Pre-bookkeep. + RenderPassInfo *pass_info = VersatileResource::allocate(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 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 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 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 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 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 p_attachment_clears, VectorView 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 : ▭ + + 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 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 p_color_attachments, + BitField p_dynamic_state, + RenderPassID p_render_pass, + uint32_t p_render_subpass, + VectorView 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 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> 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 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 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> 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 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 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 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 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(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 *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 &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 00000000000..bd195728783 --- /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 +#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED +#include "D3D12MemAlloc.h" + +#include + +#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 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 draw; + ComPtr draw_indexed; + ComPtr dispatch; + } indirect_cmd_signatures; + + /****************/ + /**** MEMORY ****/ + /****************/ + + ComPtr 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> 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 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 resource; + ComPtr 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> res_barriers_requests_allocator; + HashMap, decltype(res_barriers_requests_allocator)> res_barriers_requests; + + LocalVector 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 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> aliases; // Key is the DXGI format family. + } owner_info = {}; + } aliasing_hack = {}; // [[CROSS_FAMILY_ALIASING]] + + UINT mapped_subresource = UINT_MAX; + }; + + HashMap format_sample_counts_mask_cache; + + uint32_t _find_max_common_supported_sample_count(VectorView p_formats); + UINT _compute_component_mapping(const TextureView &p_view); + UINT _compute_plane_slice(DataFormat p_format, BitField 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 texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final; + + /*****************/ + /**** SAMPLER ****/ + /*****************/ +private: + LocalVector 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 input_elem_descs; + TightLocalVector vertex_buffer_strides; + }; + +public: + virtual VertexFormatID vertex_format_create(VectorView 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 p_src_stages, + BitField p_dst_stages, + VectorView p_memory_barriers, + VectorView p_buffer_barriers, + VectorView 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 cmd_allocator; + ComPtr 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> 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 p_secondary_cmd_buffers) override final; + + /*********************/ + /**** FRAMEBUFFER ****/ + /*********************/ +private: + struct FramebufferInfo { + bool is_screen = false; + Size2i size; + TightLocalVector 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 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 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 bindings; + struct { + uint32_t resources = 0; + uint32_t samplers = 0; + } num_root_params; + }; + + TightLocalVector 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 specialization_constants; + uint32_t spirv_specialization_constants_ids_mask = 0; + + HashMap> stages_bytecode; + + ComPtr root_signature; + ComPtr 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 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> &r_stages_bytecodes, + bool p_is_first_patch); + bool _shader_apply_specialization_constants( + const ShaderInfo *p_shader_info, + VectorView p_specialization_constants, + HashMap> &r_final_stages_bytecode); + bool _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector &r_dxil_blob); + +public: + virtual String shader_get_binary_cache_key() override final; + virtual Vector shader_compile_binary_from_spirv(VectorView p_spirv, const String &p_shader_name) override final; + virtual ShaderID shader_create_from_bytecode(const Vector &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 resource_states; + + struct RecentBind { + uint64_t segment_serial = 0; + uint32_t root_signature_crc = 0; + struct { + TightLocalVector resources; + TightLocalVector 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 resources_desc_info; +#endif + }; + +public: + virtual UniformSetID uniform_set_create(VectorView 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 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 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 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 p_regions) override final; + + /******************/ + /**** PIPELINE ****/ + /******************/ + + virtual void pipeline_free(PipelineID p_pipeline) override final; + +private: + HashMap pipelines_shaders; + +public: + // ----- BINDING ----- + + virtual void command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView p_data) override final; + + // ----- CACHE ----- + + virtual bool pipeline_cache_create(const Vector &p_data) override final; + virtual void pipeline_cache_free() override final; + virtual size_t pipeline_cache_query_size() override final; + virtual Vector pipeline_cache_serialize() override final; + + /*******************/ + /**** RENDERING ****/ + /*******************/ + + // ----- SUBPASS ----- + +private: + struct RenderPassInfo { + TightLocalVector attachments; + TightLocalVector subpasses; + uint32_t view_count = 0; + uint32_t max_supported_sample_count = 0; + }; + +public: + virtual RenderPassID render_pass_create(VectorView p_attachments, VectorView p_subpasses, VectorView 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 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 p_viewports) override final; + virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView p_scissors) override final; + + virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView p_attachment_clears, VectorView 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 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 p_color_attachments, + BitField p_dynamic_state, + RenderPassID p_render_pass, + uint32_t p_render_subpass, + VectorView 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 p_specialization_constants) override final; + + /*****************/ + /**** QUERIES ****/ + /*****************/ + + // ----- TIMESTAMP ----- + +private: + struct TimestampQueryPoolInfo { + ComPtr query_heap; + uint32_t query_count = 0; + ComPtr 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 aux_resource; + uint32_t segment_serial = 0; + +#ifdef DEV_ENABLED + uint32_t uniform_set_reused = 0; +#endif + }; + TightLocalVector 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 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 a076c0ac548..5e4bc986b80 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 00000000000..911efa77552 --- /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 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(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(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(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(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(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 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 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 p_vertex_attribs) { + // Pre-bookkeep. + VertexFormatInfo *vf_info = VersatileResource::allocate(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 p_src_stages, + BitField p_dst_stages, + VectorView p_memory_barriers, + VectorView p_buffer_barriers, + VectorView 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 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 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 RenderingDeviceDriverVulkan::shader_compile_binary_from_spirv(VectorView p_spirv, const String &p_shader_name) { + ShaderReflection shader_refl; + if (_reflect_spirv(p_spirv, shader_refl) != OK) { + return Vector(); + } + + ERR_FAIL_COND_V_MSG((uint32_t)shader_refl.uniform_sets.size() > limits.maxBoundDescriptorSets, Vector(), + "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> uniforms; // Set bindings. + Vector 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 &set_refl : shader_refl.uniform_sets) { + Vector 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> compressed_stages; + Vector smolv_size; + Vector 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(), "Error compressing shader stage :" + String(SHADER_STAGE_NAMES[p_spirv[i].shader_stage])); + } else { + smolv_size.push_back(smolv.size()); + { // zstd. + Vector 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 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 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 &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(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> 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(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(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 spirv; + }; + Vector 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 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 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(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 &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()); + } + HashMap &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::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 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(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 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 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 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 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 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 &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(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 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()); // 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 p_attachments, VectorView p_subpasses, VectorView 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 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 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 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 p_attachment_clears, VectorView 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 p_color_attachments, + BitField p_dynamic_state, + RenderPassID p_render_pass, + uint32_t p_render_subpass, + VectorView 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 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::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 00000000000..6d8f6fd0e03 --- /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 +#else +#include +#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 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 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 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 vk_bindings; + TightLocalVector vk_attributes; + VkPipelineVertexInputStateCreateInfo vk_create_info = {}; + }; + +public: + virtual VertexFormatID vertex_format_create(VectorView 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 p_src_stages, + BitField p_dst_stages, + VectorView p_memory_barriers, + VectorView p_buffer_barriers, + VectorView 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 secondary_cmd_pools; + HashSet 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 p_secondary_cmd_buffers) override final; + + /*********************/ + /**** FRAMEBUFFER ****/ + /*********************/ + + virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView 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 vk_stages_create_info; + TightLocalVector vk_descriptor_set_layouts; + VkPipelineLayout vk_pipeline_layout = VK_NULL_HANDLE; + }; + +public: + virtual String shader_get_binary_cache_key() override final; + virtual Vector shader_compile_binary_from_spirv(VectorView p_spirv, const String &p_shader_name) override final; + virtual ShaderID shader_create_from_bytecode(const Vector &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>; + 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 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 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 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 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 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 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 p_data) override final; + + // ----- CACHE ----- + + virtual bool pipeline_cache_create(const Vector &p_data) override final; + virtual void pipeline_cache_free() override final; + virtual size_t pipeline_cache_query_size() override final; + virtual Vector pipeline_cache_serialize() override final; + + /*******************/ + /**** RENDERING ****/ + /*******************/ + + // ----- SUBPASS ----- + + virtual RenderPassID render_pass_create(VectorView p_attachments, VectorView p_subpasses, VectorView 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 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 p_viewports) override final; + virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView p_scissors) override final; + virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView p_attachment_clears, VectorView 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 p_color_attachments, + BitField p_dynamic_state, + RenderPassID p_render_pass, + uint32_t p_render_subpass, + VectorView 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 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 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 04aeac2bfca..00000000000 --- 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 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(); - } - - dependency_map[p_depends_on].insert(p_id); - - if (!reverse_dependency_map.has(p_id)) { - reverse_dependency_map[p_id] = HashSet(); - } - - reverse_dependency_map[p_id].insert(p_depends_on); -} - -void RenderingDeviceVulkan::_free_dependencies(RID p_id) { - // Direct dependencies must be freed. - - HashMap>::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>::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, ®ion); - - 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> &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 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 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 &p_data, BitField 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 &p_data, BitField 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 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 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 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()); - - ERR_FAIL_COND_V_MSG(tex->bound, Vector(), - "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(), - "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()); - - 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(), "vmaMapMemory failed with error " + itos(vkerr) + "."); - - Vector 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 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 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 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 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 &p_attachments, const Vector &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 *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 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 attachments; - Vector 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 subpasses; - LocalVector> color_reference_array; - LocalVector> input_reference_array; - LocalVector> resolve_reference_array; - LocalVector> preserve_reference_array; - LocalVector depth_reference_array; - LocalVector vrs_reference_array; - LocalVector 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 subpass_dependencies; - - for (int i = 0; i < p_passes.size(); i++) { - const FramebufferPass *pass = &p_passes[i]; - - LocalVector &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 &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 &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 &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 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 &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 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 &p_attachments, const Vector &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::Element *E = framebuffer_format_cache.find(key); - if (E) { - // Exists, return. - return E->get(); - } - - Vector 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::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::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 &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 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 &p_texture_attachments, const Vector &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { - _THREAD_SAFE_METHOD_ - - Vector 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 &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 &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 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 &p_src_buffers, const Vector &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 &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 RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name) { - SpirvReflectionData spirv_data; - if (_reflect_spirv(p_spirv, spirv_data) != OK) { - return Vector(); - } - - ERR_FAIL_COND_V_MSG((uint32_t)spirv_data.uniforms.size() > limits.maxBoundDescriptorSets, Vector(), - "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> uniform_info; // Set bindings. - Vector 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 &spirv_set : spirv_data.uniforms) { - Vector 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> compressed_stages; - Vector smolv_size; - Vector 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(), "Error compressing shader stage :" + String(shader_stage_names[p_spirv[i].shader_stage])); - } else { - smolv_size.push_back(smolv.size()); - { // zstd. - Vector 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 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 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()); - } - - return ret; -} - -RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector &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(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> set_bindings; - Vector> 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(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 specialization_constants; - - for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) { - const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast(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> stage_spirv_data; - Vector 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 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 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::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 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 &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 &p_data, BitField 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 &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 *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 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 &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 writes; - DescriptorPoolKey pool_key; - - // To keep them alive until update call. - List> buffer_infos; - List> buffer_views; - List> image_infos; - // Used for verification to make sure a uniform set does not use a framebuffer bound texture. - LocalVector attachable_textures; - Vector mutable_sampled_textures; - Vector 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 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 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 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 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 buffer_info; - Vector 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 image_info; - Vector buffer_info; - Vector 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 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 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, ®ion); - -#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 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 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 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(), "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(), - "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, ®ion); // 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(), "vmaMapMemory failed with error " + itos(vkerr) + "."); - - Vector 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 p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector &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()); - } - 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 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 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 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 pipeline_stages = shader->pipeline_stages; - Vector specialization_info; - Vector> specialization_map_entries; - Vector 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 &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 specialization_map_entries; - Vector 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 screen_attachment; - screen_attachment.push_back(attachment); - return const_cast(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 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 &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 &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 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 &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { - Vector 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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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(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 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 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 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 p_from, BitField 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 &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 &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 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(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(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 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 -void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { - List 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 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::Element *E = owned.front(); E;) { - List::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::Iterator E = small_allocs_pools.begin(); - vmaDestroyPool(allocator, E->value); - small_allocs_pools.remove(E); - } - vmaDestroyAllocator(allocator); - - while (vertex_formats.size()) { - HashMap::Iterator temp = vertex_formats.begin(); - memdelete_arr(temp->value.bindings); - memdelete_arr(temp->value.attributes); - vertex_formats.remove(temp); - } - - for (KeyValue &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 e8ad0e4f45d..00000000000 --- 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 -#else -#include -#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> dependency_map; // IDs to IDs that depend on it. - HashMap> 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 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_owner; - uint32_t texture_upload_region_size_px = 0; - - Vector _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 &p_data, BitField p_post_barrier, bool p_use_setup_queue); - - /*****************/ - /**** SAMPLER ****/ - /*****************/ - - RID_Owner 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 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 attachments; - Vector 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 &p_attachments, const Vector &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 *r_samples = nullptr); - // This is a cache and it's never freed, it ensures - // IDs for a given format are always unique. - RBMap framebuffer_format_cache; - struct FramebufferFormat { - const RBMap::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 pass_samples; - uint32_t view_count = 1; // Number of views. - }; - - HashMap 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 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 framebuffers; - Size2 size; - uint32_t view_count; - }; - - RID_Owner 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 vertex_buffer_owner; - - struct VertexDescriptionKey { - Vector 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 vertex_format_cache; - - struct VertexDescriptionCache { - Vector vertex_formats; - VkVertexInputBindingDescription *bindings = nullptr; - VkVertexInputAttributeDescription *attributes = nullptr; - VkPipelineVertexInputStateCreateInfo create_info; - }; - - HashMap vertex_formats; - - struct VertexArray { - RID buffer; - VertexFormatID description = 0; - int vertex_count = 0; - uint32_t max_instances_allowed = 0; - - Vector buffers; // Not owned, just referenced. - Vector offsets; - }; - - RID_Owner 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 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 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 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 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 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 sets; - Vector set_formats; - Vector pipeline_stages; - Vector 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_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> 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 uniform_buffer_owner; - RID_Owner storage_buffer_owner; - - // Texture buffer needs a view. - struct TextureBuffer { - Buffer buffer; - VkBufferView view = VK_NULL_HANDLE; - }; - - RID_Owner 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 attachable_textures; // Used for validation. - Vector mutable_sampled_textures; // Used for layout change. - Vector mutable_storage_textures; // Used for layout change. - InvalidationCallback invalidated_callback = nullptr; - void *invalidated_callback_userdata = nullptr; - }; - - RID_Owner 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 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 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 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 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 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 command_buffers; // One for each frame. - }; - - Vector 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 set_formats; - Vector set_bound; - Vector 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 draw_list_bound_textures; - Vector 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 &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 &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 &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 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 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 set_formats; - Vector set_bound; - Vector 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 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 buffers_to_dispose_of; - List textures_to_dispose_of; - List framebuffers_to_dispose_of; - List samplers_to_dispose_of; - List shaders_to_dispose_of; - List buffer_views_to_dispose_of; - List uniform_sets_to_dispose_of; - List render_pipelines_to_dispose_of; - List 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 timestamp_names; - TightLocalVector timestamp_cpu_values; - uint32_t timestamp_count = 0; - TightLocalVector timestamp_result_names; - TightLocalVector timestamp_cpu_result_values; - TightLocalVector timestamp_result_values; - uint32_t timestamp_result_count = 0; - uint64_t index = 0; - }; - - uint32_t max_timestamp_query_elements = 0; - - TightLocalVector 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 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 - void _free_rids(T &p_owner, const char *p_type); - - void _finalize_command_bufers(); - void _begin_frame(); - -#ifdef DEV_ENABLED - HashMap 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> &p_data = Vector>()); - 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 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 &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Vector texture_get_data(RID p_texture, uint32_t p_layer); - - virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - - /*********************/ - /**** FRAMEBUFFER ****/ - /*********************/ - - virtual FramebufferFormatID framebuffer_format_create(const Vector &p_format, uint32_t p_view_count = 1); - virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector &p_attachments, const Vector &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 &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); - virtual RID framebuffer_create_multipass(const Vector &p_texture_attachments, const Vector &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 &p_data = Vector(), 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 &p_vertex_formats); - virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector &p_src_buffers, const Vector &p_offsets = Vector()); - - virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector &p_data = Vector(), 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 shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name = ""); - - virtual RID shader_create_from_bytecode(const Vector &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 &p_data = Vector()); - virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector &p_data = Vector(), BitField p_usage = 0); - virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector &p_data = Vector()); - - virtual RID uniform_set_create(const Vector &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 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Vector 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 p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector &p_specialization_constants = Vector()); - virtual bool render_pipeline_is_valid(RID p_pipeline); - - /**************************/ - /**** COMPUTE PIPELINE ****/ - /**************************/ - - virtual RID compute_pipeline_create(RID p_shader, const Vector &p_specialization_constants = Vector()); - 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); - 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); - - 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - - virtual void barrier(BitField p_from = BARRIER_MASK_ALL_BARRIERS, BitField 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 7a397a170de..1b1d4fa50f3 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,61 +1718,63 @@ 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 (formatCount < 1) { - free(surfFormats); - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1"); + if (p_surface) { + if (!separate_present_queue) { + present_queue = graphics_queue; + } else { + vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue); } - // 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; + // 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 (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; + } } } + + 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) { return 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); } + ld.driver = memnew(RenderingDeviceDriverVulkan(this, ld.device)); + return local_device_owner.make_rid(ld); } -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; -} - -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 2ccfd137390..ce1299a5599 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 @@ -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 local_device_owner; + RenderingDeviceDriverVulkan *driver = nullptr; + HashMap windows; uint32_t swapchainImageCount = 0; @@ -182,8 +178,8 @@ private: bool prepared = false; - Vector command_buffer_queue; - int command_buffer_count = 1; + LocalVector 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 _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(); + 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; - 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 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; - void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode); - DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const; + 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; + + 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 0570af35660..9bd2578eba6 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 9529e0e6835..340823baacd 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 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(RD_ENABLED) + context_rd = nullptr; + rendering_device = nullptr; + #if defined(VULKAN_ENABLED) - context_vulkan = nullptr; - rendering_device_vulkan = nullptr; - if (rendering_driver == "vulkan") { - ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window(); - ERR_FAIL_NULL(native_window); + context_rd = memnew(VulkanContextAndroid); + } +#endif - context_vulkan = memnew(VulkanContextAndroid); - if (context_vulkan->initialize() != OK) { - memdelete(context_vulkan); - context_vulkan = nullptr; - ERR_FAIL_MSG("Failed to initialize Vulkan context"); + 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 &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 54912212dc9..80af4f00c18 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 01e6d144381..4f9140bf3ef 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; - createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.window = p_window; +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; - VkSurfaceKHR surface; + VkAndroidSurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + createInfo.window = wpd->window; + + 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 f253149ef68..3cee3feb867 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 be4ea1e6abe..3d19222fa80 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 #else #include #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 60da16ae8c6..c31f503605b 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(RD_ENABLED) + context_rd = nullptr; + rendering_device = nullptr; + + CALayer *layer = nullptr; + + union { +#ifdef VULKAN_ENABLED + VulkanContextIOS::WindowPlatformData vulkan; +#endif + } wpd; + #if defined(VULKAN_ENABLED) - context_vulkan = nullptr; - rendering_device_vulkan = 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 = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"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 - 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; - r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Failed to create Vulkan window."); + 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())); } - rendering_device_vulkan = memnew(RenderingDeviceVulkan); - rendering_device_vulkan->initialize(context_vulkan); + Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale(); + 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(vformat("Failed to create %s window.", context_rd->get_api_name())); + } + + 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 9dc5e114976..06724d763fa 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 16ac3acbec2..a6467053052 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -50,15 +50,17 @@ #import #include -#if defined(VULKAN_ENABLED) +#if defined(RD_ENABLED) #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" - #import + +#if defined(VULKAN_ENABLED) #ifdef USE_VOLK #include #else #include #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 58dad4aad62..cdc8b618af6 100644 --- a/platform/ios/vulkan_context_ios.h +++ b/platform/ios/vulkan_context_ios.h @@ -38,10 +38,13 @@ #import 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 56f1894e06d..014e05f2e6c 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; - createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.pView = (__bridge const void *)p_metal_layer; +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; - VkSurfaceKHR surface; - VkResult err = - vkCreateIOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface); + VkIOSSurfaceCreateInfoMVK createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; + createInfo.pView = (__bridge const void *)(*wpd->layer_ptr); + + 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 bbb4b045088..1434342bbc7 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 &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; } @@ -6124,11 +6140,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(); } @@ -6302,9 +6317,9 @@ DisplayServerX11::~DisplayServerX11() { //destroy all windows for (KeyValue &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 @@ -6346,16 +6361,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 a8d134a6c70..ac2c7843f61 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 d240480f61d..3eee1706b06 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; - createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.dpy = p_display; - createInfo.window = p_window; +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; - VkSurfaceKHR surface; + VkXlibSurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + createInfo.dpy = wpd->display; + createInfo.window = wpd->window; + + 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 294fdc710e2..2390326b446 100644 --- a/platform/linuxbsd/x11/vulkan_context_x11.h +++ b/platform/linuxbsd/x11/vulkan_context_x11.h @@ -38,10 +38,14 @@ #include 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 a19e02eb21e..f8fd0f93efb 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 4936b83b590..bd92b7d4721 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 @@ -192,10 +192,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) @@ -245,9 +255,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 @@ -776,9 +786,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); @@ -795,8 +805,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 } @@ -3830,8 +3840,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 } @@ -3847,8 +3857,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; @@ -4648,12 +4658,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"); } @@ -4689,10 +4704,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(); } @@ -4726,16 +4741,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 ab019384e2e..6205877120f 100644 --- a/platform/macos/vulkan_context_macos.h +++ b/platform/macos/vulkan_context_macos.h @@ -38,10 +38,13 @@ #import 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 46a2d9f86ac..18c3bda39b2 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; - createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.pView = (__bridge const void *)p_window; +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; - VkSurfaceKHR surface; + VkMacOSSurfaceCreateInfoMVK createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + createInfo.pView = (__bridge const void *)(*wpd->view_ptr); + + 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 4acdc8e639c..801b32140a6 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 c35e8d9f969..2bec804c7c7 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 &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."); - } - wd.context_created = true; - } + VulkanContextWindows::WindowPlatformData vulkan; #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; + D3D12Context::WindowPlatformData d3d12; +#endif + } wpd; +#ifdef VULKAN_ENABLED + if (rendering_driver == "vulkan") { + wpd.vulkan.window = wd.hWnd; + wpd.vulkan.instance = hInstance; + } +#endif +#ifdef D3D12_ENABLED + 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; } @@ -4675,29 +4652,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) @@ -4780,18 +4756,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(); } @@ -4854,6 +4822,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" @@ -4892,14 +4870,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) { @@ -4909,29 +4882,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; +#ifdef RD_ENABLED + if (rendering_device) { + rendering_device->finalize(); + memdelete(rendering_device); + rendering_device = 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; - } - - 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 1e61462e958..29c2460c108 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 touch_state; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 02f062f2de3..35b88acd268 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 diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp index a60055dbec5..69f8dc23fbf 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 01ae2031e7c..29ab1d45c3d 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 00000000000..b5b3cdd88c4 --- /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 00000000000..22167be3c17 --- /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 242b0301f1f..28732695862 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 307cbd703aa..380e325ffa2 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 c2fa232eac4..a7f124c23cb 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -33,18 +33,14 @@ #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" + +//#define FORCE_FULL_BARRIER RenderingDevice *RenderingDevice::singleton = nullptr; -const char *RenderingDevice::shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = { - "Vertex", - "Fragment", - "TesselationControl", - "TesselationEvaluation", - "Compute", -}; - 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(); + } + + dependency_map[p_depends_on].insert(p_id); + + if (!reverse_dependency_map.has(p_id)) { + reverse_dependency_map[p_id] = HashSet(); + } + + reverse_dependency_map[p_id].insert(p_depends_on); +} + +void RenderingDevice::_free_dependencies(RID p_id) { + // Direct dependencies must be freed. + + HashMap>::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>::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,627 +131,5971 @@ RID RenderingDevice::shader_create_from_spirv(const Vector return shader_create_from_bytecode(bytecode); } -RID RenderingDevice::_texture_create(const Ref &p_format, const Ref &p_view, const TypedArray &p_data) { - ERR_FAIL_COND_V(p_format.is_null(), RID()); - ERR_FAIL_COND_V(p_view.is_null(), RID()); - Vector> data; - for (int i = 0; i < p_data.size(); i++) { - Vector 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); +/******************/ +/**** 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, {}, {}); } -RID RenderingDevice::_texture_create_shared(const Ref &p_view, RID p_with_texture) { - ERR_FAIL_COND_V(p_view.is_null(), RID()); +/***************************/ +/**** BUFFER MANAGEMENT ****/ +/***************************/ - return texture_create_shared(p_view->base, p_with_texture); -} +RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer, BitField &r_stages, BitField &r_access, BitField 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); -RID RenderingDevice::_texture_create_shared_from_slice(const Ref &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()); + 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); + } - return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type); -} + // 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); + } -Ref RenderingDevice::_texture_get_format(RID p_rd_texture) { - Ref rtf; - rtf.instantiate(); - rtf->base = texture_get_format(p_rd_texture); - - return rtf; -} - -RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray &p_attachments, uint32_t p_view_count) { - Vector attachments; - attachments.resize(p_attachments.size()); - - for (int i = 0; i < p_attachments.size(); i++) { - Ref 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 &p_attachments, const TypedArray &p_passes, uint32_t p_view_count) { - Vector attachments; - attachments.resize(p_attachments.size()); - - for (int i = 0; i < p_attachments.size(); i++) { - Ref af = p_attachments[i]; - ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); - attachments.write[i] = af->base; - } - - Vector passes; - for (int i = 0; i < p_passes.size(); i++) { - Ref 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 &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) { - Vector textures = Variant(p_textures); - return framebuffer_create(textures, p_format_check, p_view_count); -} - -RID RenderingDevice::_framebuffer_create_multipass(const TypedArray &p_textures, const TypedArray &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { - Vector textures = Variant(p_textures); - Vector passes; - for (int i = 0; i < p_passes.size(); i++) { - Ref 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 &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 &p_vertex_formats) { - Vector descriptions; - descriptions.resize(p_vertex_formats.size()); - - for (int i = 0; i < p_vertex_formats.size(); i++) { - Ref 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 &p_src_buffers, const Vector &p_offsets) { - Vector buffers = Variant(p_src_buffers); - - Vector 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 RenderingDevice::_shader_compile_spirv_from_source(const Ref &p_source, bool p_allow_cache) { - ERR_FAIL_COND_V(p_source.is_null(), Ref()); - - Ref 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 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); + 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 bytecode; + return buffer; } -Vector RenderingDevice::_shader_compile_binary_from_spirv(const Ref &p_spirv, const String &p_shader_name) { - ERR_FAIL_COND_V(p_spirv.is_null(), Vector()); +Error RenderingDevice::_insert_staging_block() { + StagingBufferBlock block; - Vector 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(), "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; - } - stage_data.push_back(sd); - } + 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); - return shader_compile_binary_from_spirv(stage_data, p_shader_name); + block.frame_used = 0; + block.fill_amount = 0; + + staging_buffer_blocks.insert(staging_buffer_current, block); + return OK; } -RID RenderingDevice::_shader_create_from_spirv(const Ref &p_spirv, const String &p_shader_name) { - ERR_FAIL_COND_V(p_spirv.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. - Vector 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()) { - continue; - } - stage_data.push_back(sd); - } - return shader_create_from_spirv(stage_data); -} + r_alloc_size = p_amount; -RID RenderingDevice::_uniform_set_create(const TypedArray &p_uniforms, RID p_shader, uint32_t p_shader_set) { - Vector uniforms; - uniforms.resize(p_uniforms.size()); - for (int i = 0; i < p_uniforms.size(); i++) { - Ref 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); -} + while (true) { + r_alloc_offset = 0; -Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector &p_data, BitField p_post_barrier) { - return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); -} + // 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. -static Vector _get_spec_constants(const TypedArray &p_constants) { - Vector ret; - ret.resize(p_constants.size()); - for (int i = 0; i < p_constants.size(); i++) { - Ref 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: { + 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; + } } } - sc.constant_id = c->get_constant_id(); + // All was good, break. + break; + } + + staging_buffer_used = true; + + return OK; +} + +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; + + 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; +} + +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 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 src_stages; + BitField 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."); + } + + BitField dst_stages; + BitField 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); + } + + 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; +} + +Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField 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 dst_stages; + BitField 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 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 dst_stages; + BitField 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 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 src_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT; + BitField 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(), "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(), + "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()); + + 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()); + + Vector 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 &p_data, BitField 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 &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 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> &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 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 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 &p_data, BitField 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 &p_data, BitField 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 stages; + BitField 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 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 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()); + + 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 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()); + + ERR_FAIL_COND_V_MSG(tex->bound, Vector(), + "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(), + "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()); + + 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 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()); + + 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()); + + Vector 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 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 stages; + BitField 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 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 stages; + BitField 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 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 valid_texture_stages = RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT | RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT | RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT; + constexpr BitField read_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT; + constexpr BitField read_write_access = RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT; + const BitField 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 stages; + BitField 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 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 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 &p_attachments, const Vector &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 *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 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 attachments; + LocalVector attachment_remap; + + for (int i = 0; i < p_attachments.size(); i++) { + 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); + } + + LocalVector subpasses; + subpasses.resize(p_passes.size()); + LocalVector subpass_dependencies; + + for (int i = 0; i < p_passes.size(); i++) { + 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); + } + } + + RDD::RenderPassID render_pass = driver->render_pass_create(attachments, subpasses, subpass_dependencies, p_view_count); + ERR_FAIL_COND_V(!render_pass, RDD::RenderPassID()); + + return render_pass; +} + +RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create(const Vector &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 passes; + passes.push_back(pass); + return framebuffer_format_create_multipass(p_format, passes, p_view_count); +} +RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_multipass(const Vector &p_attachments, const Vector &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::Element *E = framebuffer_format_cache.find(key); + if (E) { + // Exists, return. + return E->get(); + } + + Vector 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; +} + +RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create_empty(TextureSamples p_samples) { + FramebufferFormatKey key; + key.passes.push_back(FramebufferPass()); + + const RBMap::Element *E = framebuffer_format_cache.find(key); + if (E) { + // Exists, return. + return E->get(); + } + + LocalVector 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::TextureSamples RenderingDevice::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) { + HashMap::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]; +} + +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 &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); + } + } + } + + Vector passes; + passes.push_back(pass); + + return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count); +} + +RID RenderingDevice::framebuffer_create_multipass(const Vector &p_texture_attachments, const Vector &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { + _THREAD_SAFE_METHOD_ + + Vector 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 RenderingDevice::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 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 &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, {}); + } + } + + 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; +} + +// 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 &p_vertex_descriptions) { + _THREAD_SAFE_METHOD_ + + VertexDescriptionKey key; + key.vertex_formats = p_vertex_descriptions; + + VertexFormatID *idptr = vertex_format_cache.getptr(key); + if (idptr) { + return *idptr; + } + + HashSet 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 &p_src_buffers, const Vector &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->driver_id); + } + + 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::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector &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, {}); + } + } + + 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; + } + 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 ret; } -RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, BitField p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray &p_specialization_constants) { - PipelineRasterizationState rasterization_state; - if (p_rasterization_state.is_valid()) { - rasterization_state = p_rasterization_state->base; +String RenderingDevice::shader_get_binary_cache_key() const { + return driver->shader_get_binary_cache_key(); +} + +Vector RenderingDevice::shader_compile_binary_from_spirv(const Vector &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 &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; } - 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); - } - } + Shader *shader = shader_owner.get_or_null(id); + ERR_FAIL_NULL_V(shader, RID()); - PipelineDepthStencilState depth_stencil_state; - if (p_depth_stencil_state.is_valid()) { - depth_stencil_state = p_depth_stencil_state->base; - } + *((ShaderDescription *)shader) = shader_desc; // ShaderDescription bundle. + shader->name = name; + shader->driver_id = shader_id; + shader->layout_hash = driver->shader_get_layout_hash(shader_id); - 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 attachment = p_blend_state->attachments[i]; - if (attachment.is_valid()) { - color_blend_state.attachments.push_back(attachment->base); + 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::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); } - 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 &p_specialization_constants = TypedArray()) { - 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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { - Vector 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 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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { - Vector splits; - splits.resize(p_splits); - Vector 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 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 RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { - Vector 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()); - - Vector 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 &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 &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::_reflect_spirv(const Vector &p_spirv, SpirvReflectionData &r_reflection_data) { - r_reflection_data = {}; - - 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); - - 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."); - } - 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 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; - } - - 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]; - } - } - } - - } else if (need_block_size) { - info.length = binding.block.size; - } else { - info.length = 0; - } - - 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; - } - - 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; - } - } - - if (exists) { - continue; // Merged. - } - } - - info.stages_mask.set_flag(stage_flag); - - if (set >= (uint32_t)r_reflection_data.uniforms.size()) { - r_reflection_data.uniforms.resize(set + 1); - } - - r_reflection_data.uniforms.write[set].push_back(info); - } - } - - { - // 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 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; - } - } - - 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); - } - } - } - } - - 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 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_data.vertex_input_mask |= (1ULL << uint32_t(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 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_data.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 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 f = FileAccess::open("res://popo.spv", FileAccess::WRITE); - f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t)); - } +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); #endif + return id; +} - 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."); +RID RenderingDevice::shader_create_placeholder() { + Shader shader; + return shader_owner.make_rid(shader); +} - r_reflection_data.push_constant_size = pconstants[0]->size; - r_reflection_data.push_constant_stages_mask.set_flag(stage_flag); +uint64_t RenderingDevice::shader_get_vertex_input_attribute_mask(RID p_shader) { + _THREAD_SAFE_METHOD_ - //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size)); + 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 &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 &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 &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 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 attachable_textures; + Vector mutable_sampled_textures; + Vector 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 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 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: { + } + } + } + + 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 id; +} + +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 p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector &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()); + } + 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."); + } + + 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; + } } - // Destroy the reflection data when no longer required. - spvReflectDestroyShaderModule(&module); + ERR_FAIL_COND_V_MSG(!found, RID(), + "Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation."); } - r_reflection_data.stages_mask.set_flag(stage_flag); + } 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."); + } + + 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()); + } + + 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; + } + } + } + + 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; +} + +bool RenderingDevice::render_pipeline_is_valid(RID p_pipeline) { + _THREAD_SAFE_METHOD_ + return render_pipeline_owner.owns(p_pipeline); +} + +RID RenderingDevice::compute_pipeline_create(RID p_shader, const Vector &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; + } + } + } + + 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; +} + +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 screen_attachment; + screen_attachment.push_back(attachment); + return const_cast(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 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 &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 &p_storage_textures, bool p_constrained_to_region) { + LocalVector 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++) { + 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]); + } + } + + Rect2i region; + if (p_constrained_to_region) { + region = Rect2i(p_viewport_offset, p_viewport_size); + } else { + region = Rect2i(Point2i(), p_framebuffer->size); + } + + 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; } +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 &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { + LocalVector 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; + } + + 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); + } + + Rect2i rect = Rect2i(p_viewport_offset, p_viewport_size); + + driver->command_render_clear_attachments(p_draw_list->command_buffer, clear_attachments, rect); +} + +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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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; +} + +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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &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; +} + +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; + } + + 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 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 + + driver->command_render_set_blend_constants(dl->command_buffer, p_color); +} + +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 + + 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; + + 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; + } + + 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(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 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; +} + +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; + } + } + } + + driver->command_buffer_execute_secondary(frames[frame].draw_command_buffer, VectorView(command_buffers, draw_list_count)); + 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 RenderingDevice::draw_list_end(BitField 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 dst_stages; + BitField 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 src_stage(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); + BitField 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 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 (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 != RDD::TEXTURE_LAYOUT_GENERAL) { + BitField src_access; + + 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. + } + } + + if (texture_barrier_count) { + if (src_stages.is_empty()) { + src_stages.set_flag(RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT); + } + + driver->command_pipeline_barrier(cl->command_buffer, src_stages, RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, {}, {}, VectorView(texture_barriers, texture_barrier_count)); + } + } + +#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 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); + + 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 > 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)) + ")"); + + 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(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 stages(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT); + BitField access(RDD::BARRIER_ACCESS_SHADER_READ_BIT); + _compute_list_add_barrier(BARRIER_MASK_COMPUTE, stages, access); +} + +void RenderingDevice::_compute_list_add_barrier(BitField p_post_barrier, BitField p_stages, BitField 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)); + + } 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)); + } + } + +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#endif +} + +void RenderingDevice::compute_list_end(BitField p_post_barrier) { + ERR_FAIL_NULL(compute_list); + + BitField stages; + BitField 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 p_from, BitField p_to) { + if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) { + return; + } + + BitField src_stages; + BitField 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 dst_stages; + BitField 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 &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 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 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 file_data = FileAccess::get_file_as_bytes(pipelines_cache_file_path, &file_error); + return file_data; + } else { + return Vector(); + } +} + +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(p_data); + + self->_thread_safe_.lock(); + Vector 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 f = FileAccess::open(self->pipelines_cache_file_path, FileAccess::WRITE, nullptr); + if (f.is_valid()) { + f->store_buffer(cache_blob); + } +} + +template +void RenderingDevice::_free_rids(T &p_owner, const char *p_type) { + List 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 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::Element *E = owned.front(); E;) { + List::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::Iterator temp = vertex_formats.begin(); + driver->vertex_format_free(temp->value.driver_id); + vertex_formats.remove(temp); + } + + for (KeyValue &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() { ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared); @@ -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 &p_format, const Ref &p_view, const TypedArray &p_data) { + ERR_FAIL_COND_V(p_format.is_null(), RID()); + ERR_FAIL_COND_V(p_view.is_null(), RID()); + Vector> data; + for (int i = 0; i < p_data.size(); i++) { + Vector 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 &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 &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 RenderingDevice::_texture_get_format(RID p_rd_texture) { + Ref rtf; + rtf.instantiate(); + rtf->base = texture_get_format(p_rd_texture); + + return rtf; +} + +RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray &p_attachments, uint32_t p_view_count) { + Vector attachments; + attachments.resize(p_attachments.size()); + + for (int i = 0; i < p_attachments.size(); i++) { + Ref 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 &p_attachments, const TypedArray &p_passes, uint32_t p_view_count) { + Vector attachments; + attachments.resize(p_attachments.size()); + + for (int i = 0; i < p_attachments.size(); i++) { + Ref af = p_attachments[i]; + ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); + attachments.write[i] = af->base; + } + + Vector passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref 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 &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) { + Vector textures = Variant(p_textures); + return framebuffer_create(textures, p_format_check, p_view_count); +} + +RID RenderingDevice::_framebuffer_create_multipass(const TypedArray &p_textures, const TypedArray &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { + Vector textures = Variant(p_textures); + Vector passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref 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 &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 &p_vertex_formats) { + Vector descriptions; + descriptions.resize(p_vertex_formats.size()); + + for (int i = 0; i < p_vertex_formats.size(); i++) { + Ref 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 &p_src_buffers, const Vector &p_offsets) { + Vector buffers = Variant(p_src_buffers); + + Vector 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 RenderingDevice::_shader_compile_spirv_from_source(const Ref &p_source, bool p_allow_cache) { + ERR_FAIL_COND_V(p_source.is_null(), Ref()); + + Ref 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 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 RenderingDevice::_shader_compile_binary_from_spirv(const Ref &p_spirv, const String &p_shader_name) { + ERR_FAIL_COND_V(p_spirv.is_null(), Vector()); + + Vector 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(), "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 &p_spirv, const String &p_shader_name) { + ERR_FAIL_COND_V(p_spirv.is_null(), RID()); + + Vector 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 &p_uniforms, RID p_shader, uint32_t p_shader_set) { + Vector uniforms; + uniforms.resize(p_uniforms.size()); + for (int i = 0; i < p_uniforms.size(); i++) { + Ref 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 &p_data, BitField p_post_barrier) { + return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); +} + +static Vector _get_spec_constants(const TypedArray &p_constants) { + Vector ret; + ret.resize(p_constants.size()); + for (int i = 0; i < p_constants.size(); i++) { + Ref 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 &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, BitField p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray &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 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 &p_specialization_constants = TypedArray()) { + 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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { + Vector 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 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 &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { + Vector splits; + splits.resize(p_splits); + Vector 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 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 RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { + Vector 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()); + + Vector 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 &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 &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 b95640acc63..90ed2828c07 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> dependency_map; // IDs to IDs that depend on it. + HashMap> 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, }; +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; + }; + + Vector 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 { + RDD::BufferID driver_id; + uint32_t size = 0; + BitField usage; + }; + + Buffer *_get_buffer_from_owner(RID p_buffer, BitField &r_stages, BitField &r_access, BitField 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); + + RID_Owner uniform_buffer_owner; + RID_Owner storage_buffer_owner; + RID_Owner texture_buffer_owner; + +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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Vector 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 ****/ /*****************/ - 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 - }; + // 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. - 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 - }; + struct Texture { + RDD::TextureID driver_id; - 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), - }; + 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; - 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 - }; + Vector 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; - 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 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; - } - } - - 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; - } + BitField read_aspect_flags; + BitField barrier_aspect_flags; + bool bound = false; // Bound to framebffer. + RID owner; }; + RID_Owner texture_owner; + uint32_t texture_upload_region_size_px = 0; + + Vector _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 &p_data, BitField 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; + 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_view) const { - if (format_override != p_view.format_override) { + 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> &p_data = Vector>()) = 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 p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) = 0; + RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector> &p_data = Vector>()); + 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 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 &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Vector texture_get_data(RID p_texture, uint32_t p_layer); // CPU textures will return immediately, while GPU textures will most likely force a flush - enum TextureSliceType { - TEXTURE_SLICE_2D, - TEXTURE_SLICE_CUBEMAP, - TEXTURE_SLICE_3D, - TEXTURE_SLICE_2D_ARRAY, + bool texture_is_format_supported_for_usage(DataFormat p_format, BitField 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 + + 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + + /************************/ + /**** DRAW LISTS (I) ****/ + /************************/ + + 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 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; - - virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual Vector 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 - - virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField 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; - - 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField 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 &p_format, uint32_t p_view_count = 1) = 0; struct FramebufferPass { - enum { - ATTACHMENT_UNUSED = -1 - }; Vector color_attachments; Vector input_attachments; Vector 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 &p_attachments, const Vector &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 &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0; - virtual RID framebuffer_create_multipass(const Vector &p_texture_attachments, const Vector &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 attachments; + Vector passes; + uint32_t view_count = 1; - virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0; + 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. + } + }; + + RDD::RenderPassID _render_pass_create(const Vector &p_attachments, const Vector &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 *r_samples = nullptr); + + // This is a cache and it's never freed, it ensures + // IDs for a given format are always unique. + RBMap framebuffer_format_cache; + struct FramebufferFormat { + const RBMap::Element *E; + RDD::RenderPassID render_pass; // Here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec). + Vector pass_samples; + uint32_t view_count = 1; // Number of views. + }; + + HashMap 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 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 framebuffers; + Size2 size; + uint32_t view_count; + }; + + RID_Owner 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 &p_format, uint32_t p_view_count = 1); + FramebufferFormatID framebuffer_format_create_multipass(const Vector &p_attachments, const Vector &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 &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); + RID framebuffer_create_multipass(const Vector &p_texture_attachments, const Vector &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 sampler_owner; - 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; - 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; - } - }; - - 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; +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, - }; - - 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; - } - }; - virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector &p_data = Vector(), bool p_use_as_storage = false) = 0; - typedef int64_t VertexFormatID; - // This ID is warranted to be unique for the same formats, does not need to be freed - virtual VertexFormatID vertex_format_create(const Vector &p_vertex_formats) = 0; - virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector &p_src_buffers, const Vector &p_offsets = Vector()) = 0; +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. - enum IndexBufferFormat { - INDEX_BUFFER_FORMAT_UINT16, - INDEX_BUFFER_FORMAT_UINT32, + RID_Owner vertex_buffer_owner; + + struct VertexDescriptionKey { + Vector 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); + } }; - virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector &p_data = Vector(), 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; + 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 vertex_format_cache; + + struct VertexDescriptionCache { + Vector vertex_formats; + RDD::VertexFormatID driver_id; + }; + + HashMap vertex_formats; + + struct VertexArray { + RID buffer; + VertexFormatID description; + int vertex_count = 0; + uint32_t max_instances_allowed = 0; + + Vector buffers; // Not owned, just referenced. + Vector offsets; + }; + + RID_Owner 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 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 index_array_owner; + +public: + RID vertex_buffer_create(uint32_t p_size_bytes, const Vector &p_data = Vector(), 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 &p_vertex_descriptions); + RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector &p_src_buffers, const Vector &p_offsets = Vector()); + + RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector &p_data = Vector(), 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 ****/ /****************/ + // 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. + +private: + struct UniformSetFormat { + Vector 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 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 set_formats; + }; + + String _shader_uniform_debug(RID p_shader, int p_set = -1); + + RID_Owner shader_owner; + +#ifndef DISABLE_DEPRECATED + BitField _convert_barrier_mask_81356(BitField p_old_barrier); + void _draw_list_end_bind_compat_81356(BitField p_post_barrier); + void _compute_list_end_bind_compat_81356(BitField p_post_barrier); + void _barrier_bind_compat_81356(BitField p_from, BitField p_to); +#endif + +public: + ApiContextRD *get_context() const { return context; } + const Capabilities *get_device_capabilities() const { return &device_capabilities; }; - 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, - }; - virtual bool has_feature(const Features p_feature) const = 0; + bool has_feature(const Features p_feature) const; - virtual Vector 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; + Vector 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 spir_v; + String shader_get_binary_cache_key() const; + Vector shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name = ""); - ShaderStageSPIRVData() { - shader_stage = SHADER_STAGE_VERTEX; - } - }; + RID shader_create_from_spirv(const Vector &p_spirv, const String &p_shader_name = ""); + RID shader_create_from_bytecode(const Vector &p_shader_binary, RID p_placeholder = RID()); + RID shader_create_placeholder(); - virtual String shader_get_binary_cache_key() const = 0; - virtual Vector shader_compile_binary_from_spirv(const Vector &p_spirv, const String &p_shader_name = "") = 0; - - virtual RID shader_create_from_spirv(const Vector &p_spirv, const String &p_shader_name = ""); - virtual RID shader_create_from_bytecode(const Vector &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 &p_data = Vector()) = 0; - virtual RID storage_buffer_create(uint32_t p_size, const Vector &p_data = Vector(), BitField p_usage = 0) = 0; - virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector &p_data = Vector()) = 0; + RID uniform_buffer_create(uint32_t p_size_bytes, const Vector &p_data = Vector()); + RID storage_buffer_create(uint32_t p_size, const Vector &p_data = Vector(), BitField p_usage = 0); + RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector &p_data = Vector()); 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,365 +871,247 @@ 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 &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. - 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 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 p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual Vector 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. - - /******************************************/ - /**** PIPELINE SPECIALIZATION CONSTANT ****/ - /******************************************/ - - 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; - union { - uint32_t int_value; - float float_value; - bool bool_value; + 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; }; - PipelineSpecializationConstant() { - type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; - constant_id = 0; - int_value = 0; - } + LocalVector attachable_textures; // Used for validation. + Vector mutable_sampled_textures; // Used for layout change. + Vector mutable_storage_textures; // Used for layout change. + InvalidationCallback invalidated_callback = nullptr; + void *invalidated_callback_userdata = nullptr; }; - /*************************/ - /**** RENDER PIPELINE ****/ - /*************************/ + RID_Owner uniform_set_owner; - 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 +public: + RID uniform_set_create(const Vector &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 set_formats; + RDD::PipelineID driver_id; + uint32_t push_constant_size = 0; }; - //disable optimization, tessellate control points + RID_Owner render_pipeline_owner; - enum PolygonCullMode { - POLYGON_CULL_DISABLED, - POLYGON_CULL_FRONT, - POLYGON_CULL_BACK, + 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 _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 set_formats; + RDD::PipelineID driver_id; + uint32_t push_constant_size = 0; + uint32_t local_group_size[3] = { 0, 0, 0 }; }; - enum PolygonFrontFace { - POLYGON_FRONT_FACE_CLOCKWISE, - POLYGON_FRONT_FACE_COUNTER_CLOCKWISE, - }; + RID_Owner compute_pipeline_owner; - 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 - }; +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 p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector &p_specialization_constants = Vector()); + bool render_pipeline_is_valid(RID p_pipeline); - 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 - }; - - 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 //not an actual operator, just the amount of operators :D - }; - - 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; - } - }; - - struct PipelineMultisampleState { - TextureSamples sample_count; - bool enable_sample_shading; - float min_sample_shading; - Vector 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; - } - }; - - 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; - } - }; - - 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; - } - }; - - 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; - } - }; - - 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 attachments; //one per render target texture - Color blend_constant; - - PipelineColorBlendState() { - enable_logic_op = false; - logic_op = LOGIC_OP_CLEAR; - } - }; - - 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), - }; - - 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 p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector &p_specialization_constants = Vector()) = 0; - - /**************************/ - /**** COMPUTE PIPELINE ****/ - /**************************/ - - virtual RID compute_pipeline_create(RID p_shader, const Vector &p_specialization_constants = Vector()) = 0; - virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0; + RID compute_pipeline_create(RID p_shader, const Vector &p_specialization_constants = Vector()); + bool compute_pipeline_is_valid(RID p_pipeline); /****************/ /**** SCREEN ****/ /****************/ - 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; + 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; - /********************/ - /**** DRAW LISTS ****/ - /********************/ - - 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 - }; - - 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 - }; + /*************************/ + /**** DRAW LISTS (II) ****/ + /*************************/ typedef int64_t DrawListID; - 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()) = 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()) = 0; +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. - 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; + // 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. - virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 0; + struct SplitDrawListAllocator { + RDD::CommandPoolID command_pool; + Vector command_buffers; // One for each frame. + }; - virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0; - virtual void draw_list_disable_scissor(DrawListID p_list) = 0; + Vector split_draw_list_allocators; - 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; + struct DrawList { + RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer. + Rect2i viewport; + bool viewport_set = false; - virtual void draw_list_end(BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; + 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; + }; + + 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 set_formats; + Vector set_bound; + Vector 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; + 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; + + bool draw_list_split = false; + Vector draw_list_bound_textures; + Vector 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 &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 &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 &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); + +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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); + 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 &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); + + 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); + + void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0); + + void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect); + void draw_list_disable_scissor(DrawListID p_list); + + 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); + + void draw_list_end(BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); /***********************/ /**** COMPUTE LISTS ****/ @@ -1212,99 +1119,184 @@ public: typedef int64_t ComputeListID; - 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; +private: + struct ComputeList { + RDD::CommandBufferID command_buffer; // If persistent, this is owned, otherwise it's shared with the ringbuffer. - virtual void compute_list_end(BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; + 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; + }; - virtual void barrier(BitField p_from = BARRIER_MASK_ALL_BARRIERS, BitField p_to = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual void full_barrier() = 0; + struct State { + HashSet 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; - /***************/ - /**** FREE! ****/ - /***************/ +#ifdef DEBUG_ENABLED + struct Validation { + bool active = true; // Means command buffer was not closed, so you can keep adding things. + Vector set_formats; + Vector set_bound; + Vector 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 void free(RID p_id) = 0; + ComputeList *compute_list = nullptr; + + void _compute_list_add_barrier(BitField p_post_barrier, BitField p_stages, BitField p_access); + +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); + + void compute_list_end(BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + + void barrier(BitField p_from = BARRIER_MASK_ALL_BARRIERS, BitField p_to = BARRIER_MASK_ALL_BARRIERS); + void full_barrier(); + + /**************************/ + /**** 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. + +private: + struct Frame { + // List in usage order, from last to free to first to free. + List buffers_to_dispose_of; + List textures_to_dispose_of; + List framebuffers_to_dispose_of; + List samplers_to_dispose_of; + List shaders_to_dispose_of; + List uniform_sets_to_dispose_of; + List render_pipelines_to_dispose_of; + List 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; + }; + + RDD::QueryPoolID timestamp_pool; + + TightLocalVector timestamp_names; + TightLocalVector timestamp_cpu_values; + uint32_t timestamp_count = 0; + TightLocalVector timestamp_result_names; + TightLocalVector timestamp_cpu_result_values; + TightLocalVector timestamp_result_values; + uint32_t timestamp_result_count = 0; + uint64_t index = 0; + }; + + uint32_t max_timestamp_query_elements = 0; + + TightLocalVector 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); + + ApiContextRD *context = nullptr; + + uint64_t texture_memory = 0; + uint64_t buffer_memory = 0; + + void _free_internal(RID p_id); + void _flush(bool p_current_frame); + + bool screen_prepared = false; + + template + void _free_rids(T &p_owner, const char *p_type); + + void _finalize_command_bufers(); + void _begin_frame(); + +#ifdef DEV_ENABLED + HashMap resource_names; +#endif + +public: + void initialize(ApiContextRD *p_context, bool p_local_device = false); + void finalize(); + + 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(); + ~RenderingDevice(); -protected: - static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX]; +private: + /*****************/ + /**** BINDERS ****/ + /*****************/ - static const uint32_t MAX_UNIFORM_SETS = 16; - - //binders to script API RID _texture_create(const Ref &p_format, const Ref &p_view, const TypedArray &p_data = Array()); RID _texture_create_shared(const Ref &p_view, RID p_with_texture); RID _texture_create_shared_from_slice(const Ref &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 &p_attachments, const TypedArray &p_passes, uint32_t p_view_count); RID _framebuffer_create(const TypedArray &p_textures, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); RID _framebuffer_create_multipass(const TypedArray &p_textures, const TypedArray &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); + RID _sampler_create(const Ref &p_state); + VertexFormatID _vertex_format_create(const TypedArray &p_vertex_formats); RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray &p_src_buffers, const Vector &p_offsets = Vector()); @@ -1358,7 +1353,7 @@ protected: RID _uniform_set_create(const TypedArray &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 &p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + Error _buffer_update_bind(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector &p_data, BitField 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 &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, BitField p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray &p_specialization_constants); RID _compute_pipeline_create(RID p_shader, const TypedArray &p_specialization_constants); @@ -1368,46 +1363,6 @@ protected: void _draw_list_set_push_constant(DrawListID p_list, const Vector &p_data, uint32_t p_data_size); void _compute_list_set_push_constant(ComputeListID p_list, const Vector &p_data, uint32_t p_data_size); Vector _draw_list_switch_to_next_pass_split(uint32_t p_splits); - - struct SpirvReflectionData { - BitField 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 push_constant_stages_mask; - - struct Uniform { - UniformType type; - uint32_t binding; - BitField stages_mask; - uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements). - bool writable; - }; - Vector> uniforms; - - struct SpecializationConstant { - PipelineSpecializationConstantType type; - uint32_t constant_id; - union { - uint32_t int_value; - float float_value; - bool bool_value; - }; - BitField stages_mask; - }; - Vector specialization_constants; - }; - - Error _reflect_spirv(const Vector &p_spirv, SpirvReflectionData &r_reflection_data); - -#ifndef DISABLE_DEPRECATED - BitField _convert_barrier_mask_81356(BitField p_old_barrier); - void _draw_list_end_bind_compat_81356(BitField p_post_barrier); - void _compute_list_end_bind_compat_81356(BitField p_post_barrier); - void _barrier_bind_compat_81356(BitField p_from, BitField 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 737a874abc9..5f21207579d 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 00000000000..c8b7980633f --- /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 00000000000..dabd0c08678 --- /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 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 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 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 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 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 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> uniform_sets; + Vector specialization_constants; + }; + + struct ShaderReflection : public ShaderDescription { + BitField stages; + BitField 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 00000000000..9e05a6a133c --- /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 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 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 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 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 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 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 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 00000000000..bb71a29bbc1 --- /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 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 + +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 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 &p_lv) : + _ptr(p_lv.ptr()), _size(p_lv.size()) {} + VectorView(const LocalVector &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 +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 + static T *allocate(PagedAllocator &p_allocator) { + T *obj = (T *)p_allocator.alloc(); + *obj = T(); + return obj; + } + + template + static void free(PagedAllocator &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 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 aspect; + uint32_t mipmap = 0; + uint32_t base_layer = 0; + uint32_t layer_count = 0; + }; + + struct TextureSubresourceRange { + BitField 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 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 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 src_access; + BitField dst_access; + }; + + struct BufferBarrier { + BufferID buffer; + BitField src_access; + BitField dst_access; + uint64_t offset = 0; + uint64_t size = 0; + }; + + struct TextureBarrier { + TextureID texture; + BitField src_access; + BitField 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 p_src_stages, + BitField p_dst_stages, + VectorView p_memory_barriers, + VectorView p_buffer_barriers, + VectorView 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 p_secondary_cmd_buffers) = 0; + + /*********************/ + /**** FRAMEBUFFER ****/ + /*********************/ + + virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView 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 shader_compile_binary_from_spirv(VectorView p_spirv, const String &p_shader_name) = 0; + virtual ShaderID shader_create_from_bytecode(const Vector &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 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 ids; + }; + + virtual UniformSetID uniform_set_create(VectorView 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 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 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 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 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 p_data) = 0; + + // ----- CACHE ----- + + virtual bool pipeline_cache_create(const Vector &p_data) = 0; + virtual void pipeline_cache_free() = 0; + virtual size_t pipeline_cache_query_size() = 0; + virtual Vector 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 aspect; + }; + + struct Subpass { + LocalVector input_references; + LocalVector color_references; + AttachmentReference depth_stencil_reference; + LocalVector resolve_references; + LocalVector preserve_attachments; + AttachmentReference vrs_reference; + }; + + struct SubpassDependency { + uint32_t src_subpass = 0xffffffff; + uint32_t dst_subpass = 0xffffffff; + BitField src_stages; + BitField dst_stages; + BitField src_access; + BitField dst_access; + }; + + virtual RenderPassID render_pass_create(VectorView p_attachments, VectorView p_subpasses, VectorView 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 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 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 p_viewports) = 0; + virtual void command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView p_scissors) = 0; + virtual void command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView p_attachment_clears, VectorView 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 p_color_attachments, + BitField p_dynamic_state, + RenderPassID p_render_pass, + uint32_t p_render_subpass, + VectorView 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 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 8b8f40aff39..00d88206057 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 8e2488091a4..4d19e0e7276 100644 --- a/thirdparty/d3d12ma/D3D12MemAlloc.cpp +++ b/thirdparty/d3d12ma/D3D12MemAlloc.cpp @@ -33,6 +33,14 @@ #include #endif +/* GODOT start */ +#if !defined(_MSC_VER) +#include + +#include +#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 bbe273d333e..00000000000 --- 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(Left); - top = 0; - front = 0; - right = static_cast(Right); - bottom = 1; - back = 1; - } - explicit CD3DX12_BOX( - LONG Left, - LONG Top, - LONG Right, - LONG Bottom ) noexcept - { - left = static_cast(Left); - top = static_cast(Top); - front = 0; - right = static_cast(Right); - bottom = static_cast(Bottom); - back = 1; - } - explicit CD3DX12_BOX( - LONG Left, - LONG Top, - LONG Front, - LONG Right, - LONG Bottom, - LONG Back ) noexcept - { - left = static_cast(Left); - top = static_cast(Top); - front = static_cast(Front); - right = static_cast(Right); - bottom = static_cast(Bottom); - back = static_cast(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 -inline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept -{ - MipSlice = static_cast(Subresource % MipLevels); - ArraySlice = static_cast((Subresource / MipLevels) % ArraySize); - PlaneSlice = static_cast(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(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(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(pDest->pData) + pDest->SlicePitch * z; - auto pSrcSlice = static_cast(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(pDest->pData) + pDest->SlicePitch * z; - auto pSrcSlice = (static_cast(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(&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(&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(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(&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(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(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources; - if (MemToAlloc > SIZE_MAX) - { - return 0; - } - void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast(MemToAlloc)); - if (pMem == nullptr) - { - return 0; - } - auto pLayouts = static_cast(pMem); - auto pRowSizesInBytes = reinterpret_cast(pLayouts + NumSubresources); - auto pNumRows = reinterpret_cast(pRowSizesInBytes + NumSubresources); - - const auto Desc = pDestinationResource->GetDesc(); - ID3D12Device* pDevice = nullptr; - pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast(&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(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources; - if (MemToAlloc > SIZE_MAX) - { - return 0; - } - void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast(MemToAlloc)); - if (pMem == nullptr) - { - return 0; - } - auto pLayouts = static_cast(pMem); - auto pRowSizesInBytes = reinterpret_cast(pLayouts + NumSubresources); - auto pNumRows = reinterpret_cast(pRowSizesInBytes + NumSubresources); - - const auto Desc = pDestinationResource->GetDesc(); - ID3D12Device* pDevice = nullptr; - pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast(&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 -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(&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 -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(&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 -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(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(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(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(const_cast(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 -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(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(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(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(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(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(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(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(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(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(Desc.pPipelineStateSubobjectStream)+CurOffset; - auto SubobjectType = *reinterpret_cast(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(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS: - pCallbacks->VSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS: - pCallbacks->PSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS: - pCallbacks->DSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS: - pCallbacks->HSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS: - pCallbacks->GSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS: - pCallbacks->CSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS: - pCallbacks->ASCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS: - pCallbacks->MSCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT: - pCallbacks->StreamOutputCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND: - pCallbacks->BlendStateCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK: - pCallbacks->SampleMaskCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER: - pCallbacks->RasterizerStateCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL: - pCallbacks->DepthStencilStateCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1: - pCallbacks->DepthStencilState1Cb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2: - pCallbacks->DepthStencilState2Cb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT: - pCallbacks->InputLayoutCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE: - pCallbacks->IBStripCutValueCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY: - pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS: - pCallbacks->RTVFormatsCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT: - pCallbacks->DSVFormatCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC: - pCallbacks->SampleDescCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK: - pCallbacks->NodeMaskCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO: - pCallbacks->CachedPSOCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS: - pCallbacks->FlagsCb(*reinterpret_cast(pStream)); - SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags); - break; - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING: - pCallbacks->ViewInstancingCb(*reinterpret_cast(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 -#include -#include -#include -#ifndef D3DX12_USE_ATL -#include -#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 -#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(m_SubobjectArray[i].pDesc); - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation; - auto pWrapper = - static_cast(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(*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(); - // 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 - 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 m_SubobjectList; // Pointers to list nodes handed out so - // these can be edited live - std::vector m_SubobjectArray; // Built at the end, copying list contents - - std::list - 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 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> 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 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(m_Exports.size()); - } - template - 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 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(m_Exports.size()); - } - template - 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 m_CollectionRef; - CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings; - std::vector 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 - 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 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 - 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 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 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 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 - -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 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 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 m_dProtectedResourceSessionSupport; - D3D12_FEATURE_DATA_ROOT_SIGNATURE m_dRootSignature; - std::vector 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 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 m_dProtectedResourceSessionTypeCount; // Cat2 NodeIndex - std::vector 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(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(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, 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(0); - } - return result; - } - } - - // Shader model may not be supported. Continue the rest initializations - m_dShaderModel.HighestShaderModel = static_cast(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(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(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(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(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 00000000000..4d04c3a7a50 --- /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 + +#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_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_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)<>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)<>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_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)))) + +// 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)<>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_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)<> \ + (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_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_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_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_TYPE_SHIFT)) + +// ENCODER MACRO: Store operand type in OperandToken0. +#define ENCODE_D3D10_SB_OPERAND_TYPE(OperandType) (((OperandType)<>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_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_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)<> 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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of resources in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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)<[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of resources in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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)<> \ + (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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of samplers in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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_INPUT_INTERPOLATION_MODE_SHIFT)) + +// ENCODER MACRO: Encode interpolation mode for a register. +#define ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE(InterpolationMode) (((InterpolationMode)<[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of constant buffers in the space +// 3 : the upper bound (inclusive) of this range +// As opposed to when the cb#[] is used in shader instructions: (cb[][]) +// 1 : variable ID being used (matches dcl) +// 2 : absolute index of constant buffer within space (may be dynamically indexed) +// 3 : 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_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_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)<>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_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_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_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_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)<>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)<>D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT) ? true : false) +#define ENCODE_D3D11_SB_INTERFACE_INDEXED_BIT(IndexedBit) (((IndexedBit)<>D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT)) +#define ENCODE_D3D11_SB_INTERFACE_TABLE_LENGTH(TableLength) (((TableLength)<>D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT)) +#define ENCODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(ArrayLength) (((ArrayLength)<[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of UAV's in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of UAV's in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of UAV's in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of resources in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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[:]) +// 1 : variable ID being declared +// 2 : the lower bound of the range of resources in the space +// 3 : 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[]): +// 1 : variable ID being used (matches dcl) +// 2 : 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 similarity index 88% rename from thirdparty/directx_headers/d3d12.h rename to thirdparty/directx_headers/include/directx/d3d12.h index 07355f558c6..d57513b7f80 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 similarity index 100% rename from thirdparty/directx_headers/d3d12compatibility.h rename to thirdparty/directx_headers/include/directx/d3d12compatibility.h diff --git a/thirdparty/directx_headers/d3d12sdklayers.h b/thirdparty/directx_headers/include/directx/d3d12sdklayers.h similarity index 97% rename from thirdparty/directx_headers/d3d12sdklayers.h rename to thirdparty/directx_headers/include/directx/d3d12sdklayers.h index b25a8f6e5d8..06aa091b558 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 similarity index 100% rename from thirdparty/directx_headers/d3d12shader.h rename to thirdparty/directx_headers/include/directx/d3d12shader.h diff --git a/thirdparty/directx_headers/d3d12video.h b/thirdparty/directx_headers/include/directx/d3d12video.h similarity index 91% rename from thirdparty/directx_headers/d3d12video.h rename to thirdparty/directx_headers/include/directx/d3d12video.h index add372e3819..fe9a17377c9 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); @@ -6319,6 +6331,463 @@ DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1, 0x6936ff0f, 0x45b1, 0x4163, DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2, 0x0c5f2aa1, 0xe541, 0x4089, 0xbb, 0x7b, 0x98, 0x11, 0x0a, 0x19, 0xd7, 0xc8); DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2, 0x17127009, 0xa00f, 0x4ce1, 0x99, 0x4e, 0xbf, 0x40, 0x81, 0xf6, 0xf3, 0xf0); DEFINE_GUID(D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420, 0x2d80bed6, 0x9cac, 0x4835, 0x9e, 0x91, 0x32, 0x7b, 0xbc, 0x4f, 0x9e, 0xe8); +typedef +enum D3D12_VIDEO_ENCODER_AV1_PROFILE + { + D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN = 0, + D3D12_VIDEO_ENCODER_AV1_PROFILE_HIGH = 1, + D3D12_VIDEO_ENCODER_AV1_PROFILE_PROFESSIONAL = 2 + } D3D12_VIDEO_ENCODER_AV1_PROFILE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_LEVELS + { + D3D12_VIDEO_ENCODER_AV1_LEVELS_2_0 = 0, + D3D12_VIDEO_ENCODER_AV1_LEVELS_2_1 = 1, + D3D12_VIDEO_ENCODER_AV1_LEVELS_2_2 = 2, + D3D12_VIDEO_ENCODER_AV1_LEVELS_2_3 = 3, + D3D12_VIDEO_ENCODER_AV1_LEVELS_3_0 = 4, + D3D12_VIDEO_ENCODER_AV1_LEVELS_3_1 = 5, + D3D12_VIDEO_ENCODER_AV1_LEVELS_3_2 = 6, + D3D12_VIDEO_ENCODER_AV1_LEVELS_3_3 = 7, + D3D12_VIDEO_ENCODER_AV1_LEVELS_4_0 = 8, + D3D12_VIDEO_ENCODER_AV1_LEVELS_4_1 = 9, + D3D12_VIDEO_ENCODER_AV1_LEVELS_4_2 = 10, + D3D12_VIDEO_ENCODER_AV1_LEVELS_4_3 = 11, + D3D12_VIDEO_ENCODER_AV1_LEVELS_5_0 = 12, + D3D12_VIDEO_ENCODER_AV1_LEVELS_5_1 = 13, + D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2 = 14, + D3D12_VIDEO_ENCODER_AV1_LEVELS_5_3 = 15, + D3D12_VIDEO_ENCODER_AV1_LEVELS_6_0 = 16, + D3D12_VIDEO_ENCODER_AV1_LEVELS_6_1 = 17, + D3D12_VIDEO_ENCODER_AV1_LEVELS_6_2 = 18, + D3D12_VIDEO_ENCODER_AV1_LEVELS_6_3 = 19, + D3D12_VIDEO_ENCODER_AV1_LEVELS_7_0 = 20, + D3D12_VIDEO_ENCODER_AV1_LEVELS_7_1 = 21, + D3D12_VIDEO_ENCODER_AV1_LEVELS_7_2 = 22, + D3D12_VIDEO_ENCODER_AV1_LEVELS_7_3 = 23 + } D3D12_VIDEO_ENCODER_AV1_LEVELS; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_TIER + { + D3D12_VIDEO_ENCODER_AV1_TIER_MAIN = 0, + D3D12_VIDEO_ENCODER_AV1_TIER_HIGH = 1 + } D3D12_VIDEO_ENCODER_AV1_TIER; + +typedef struct D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS + { + D3D12_VIDEO_ENCODER_AV1_LEVELS Level; + D3D12_VIDEO_ENCODER_AV1_TIER Tier; + } D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK = 0x1, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA = 0x2, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER = 0x4, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND = 0x8, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND = 0x10, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION = 0x20, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER = 0x40, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP = 0x80, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS = 0x100, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION = 0x200, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER = 0x400, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING = 0x800, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING = 0x1000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY = 0x2000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS = 0x4000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS = 0x8000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION = 0x10000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION = 0x20000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS = 0x40000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS = 0x80000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX = 0x100000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET = 0x200000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE = 0x400000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV = 0x800000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SKIP_MODE_PRESENT = 0x1000000, + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DELTA_LF_PARAMS = 0x2000000 + } D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_TX_MODE + { + D3D12_VIDEO_ENCODER_AV1_TX_MODE_ONLY4x4 = 0, + D3D12_VIDEO_ENCODER_AV1_TX_MODE_LARGEST = 1, + D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT = 2 + } D3D12_VIDEO_ENCODER_AV1_TX_MODE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_ONLY4x4 = ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_ONLY4x4 ) , + D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_LARGEST = ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_LARGEST ) , + D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_SELECT = ( 1 << D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT ) + } D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS + { + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP = 0, + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SMOOTH = 1, + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SHARP = 2, + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_BILINEAR = 3, + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE = 4 + } D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP = ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP ) , + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SMOOTH = ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SMOOTH ) , + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SHARP = ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP_SHARP ) , + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_BILINEAR = ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_BILINEAR ) , + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_SWITCHABLE = ( 1 << D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE ) + } D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE + { + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_4x4 = 0, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_8x8 = 1, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_16x16 = 2, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_32x32 = 3, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE_64x64 = 4 + } D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE + { + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_DISABLED = 0, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_Q = 1, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_V = 2, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_H = 3, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_U = 4, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_V = 5, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_REF_FRAME = 6, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_SKIP = 7, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_GLOBALMV = 8 + } D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_DISABLED = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_DISABLED ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_Q = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_Q ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_V = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_V ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_H = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_Y_H ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_U = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_U ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_V = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_LF_V ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_REF_FRAME = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_REF_FRAME ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_SKIP = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_SKIP ) , + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_GLOBALMV = ( 1 << D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_ALT_GLOBALMV ) + } D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE + { + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED = 0, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_SWITCHABLE = 1, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_WIENER = 2, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_SGRPROJ = 3 + } D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE + { + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_DISABLED = 0, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_32x32 = 1, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_64x64 = 2, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_128x128 = 3, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_256x256 = 4 + } D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_NOT_SUPPORTED = 0, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_32x32 = 0x1, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_64x64 = 0x2, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_128x128 = 0x4, + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAG_256x256 = 0x8 + } D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION + { + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_IDENTITY = 0, + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_TRANSLATION = 1, + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_ROTZOOM = 2, + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_AFFINE = 3 + } D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_IDENTITY = ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_IDENTITY ) , + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_TRANSLATION = ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_TRANSLATION ) , + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_ROTZOOM = ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_ROTZOOM ) , + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAG_AFFINE = ( 1 << D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_AFFINE ) + } D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION = 0x1, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION_DELTA = 0x2, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER = 0x4, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER_DELTA = 0x8, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CDEF_DATA = 0x10, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CONTEXT_UPDATE_TILE_ID = 0x20, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_COMPOUND_PREDICTION_MODE = 0x40, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_PRIMARY_REF_FRAME = 0x80, + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_REFERENCE_INDICES = 0x100 + } D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS); +typedef struct D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT + { + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS SupportedFeatureFlags; + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS RequiredFeatureFlags; + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS SupportedInterpolationFilters; + D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS SupportedRestorationParams[ 3 ][ 3 ]; + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAGS SupportedSegmentationModes; + D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS SupportedTxModes[ 4 ]; + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_BLOCK_SIZE SegmentationBlockSize; + D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS PostEncodeValuesFlags; + UINT MaxTemporalLayers; + UINT MaxSpatialLayers; + } D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE + { + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME = 0, + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME = 1, + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME = 2, + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME = 3 + } D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_KEY_FRAME = ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME ) , + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_INTER_FRAME = ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME ) , + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_INTRA_ONLY_FRAME = ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME ) , + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAG_SWITCH_FRAME = ( 1 << D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME ) + } D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS); +typedef +enum D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE + { + D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE = 0, + D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_COMPOUND_REFERENCE = 1 + } D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE; + +typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT + { + D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE PredictionMode; + UINT MaxUniqueReferencesPerFrame; + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_FLAGS SupportedFrameTypes; + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_FLAGS SupportedReferenceWarpedMotionFlags; + } D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT; + +typedef struct D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION + { + D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS FeatureFlags; + UINT OrderHintBitsMinus1; + } D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION; + +typedef struct D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE + { + UINT IntraDistance; + UINT InterFramePeriod; + } D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE; + +typedef struct D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO + { + D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION TransformationType; + INT TransformationMatrix[ 8 ]; + BOOL InvalidAffineSet; + } D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO; + +typedef struct D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR + { + UINT ReconstructedPictureResourceIndex; + UINT TemporalLayerIndexPlus1; + UINT SpatialLayerIndexPlus1; + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE FrameType; + D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO WarpedMotionInfo; + UINT OrderHint; + UINT PictureIndex; + } D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR; + +typedef +enum D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE = 0x1, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_CDF_UPDATE = 0x2, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING = 0x4, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE = 0x8, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS = 0x10, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS = 0x20, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY = 0x40, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_USE_SUPER_RESOLUTION = 0x80, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_FRAME_END_UPDATE_CDF = 0x100, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO = 0x200, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_CUSTOM = 0x400, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION = 0x800, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET = 0x1000, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE = 0x2000, + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV = 0x4000 + } D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS); +typedef struct D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG + { + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE FrameRestorationType[ 3 ]; + D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE LoopRestorationPixelSize[ 3 ]; + } D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA + { + UINT64 EnabledFeatures; + INT64 FeatureValue[ 8 ]; + } D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA; + +typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG + { + UINT64 UpdateMap; + UINT64 TemporalUpdate; + UINT64 UpdateData; + UINT64 NumSegments; + D3D12_VIDEO_ENCODER_AV1_SEGMENT_DATA SegmentsData[ 8 ]; + } D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP + { + UINT SegmentsMapByteSize; + UINT8 *pSegmentsMap; + } D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP; + +typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG + { + UINT64 LoopFilterLevel[ 2 ]; + UINT64 LoopFilterLevelU; + UINT64 LoopFilterLevelV; + UINT64 LoopFilterSharpnessLevel; + UINT64 LoopFilterDeltaEnabled; + UINT64 UpdateRefDelta; + INT64 RefDeltas[ 8 ]; + UINT64 UpdateModeDelta; + INT64 ModeDeltas[ 2 ]; + } D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG + { + UINT64 DeltaLFPresent; + UINT64 DeltaLFMulti; + UINT64 DeltaLFRes; + } D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG + { + UINT64 BaseQIndex; + INT64 YDCDeltaQ; + INT64 UDCDeltaQ; + INT64 UACDeltaQ; + INT64 VDCDeltaQ; + INT64 VACDeltaQ; + UINT64 UsingQMatrix; + UINT64 QMY; + UINT64 QMU; + UINT64 QMV; + } D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG + { + UINT64 DeltaQPresent; + UINT64 DeltaQRes; + } D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG + { + UINT64 CdefBits; + UINT64 CdefDampingMinus3; + UINT64 CdefYPriStrength[ 8 ]; + UINT64 CdefUVPriStrength[ 8 ]; + UINT64 CdefYSecStrength[ 8 ]; + UINT64 CdefUVSecStrength[ 8 ]; + } D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG; + +typedef struct D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA + { + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS Flags; + D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE FrameType; + D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE CompoundPredictionType; + D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS InterpolationFilter; + D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG FrameRestorationConfig; + D3D12_VIDEO_ENCODER_AV1_TX_MODE TxMode; + UINT SuperResDenominator; + UINT OrderHint; + UINT PictureIndex; + UINT TemporalLayerIndexPlus1; + UINT SpatialLayerIndexPlus1; + D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR ReferenceFramesReconPictureDescriptors[ 8 ]; + UINT ReferenceIndices[ 7 ]; + UINT PrimaryRefFrame; + UINT RefreshFrameFlags; + D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG LoopFilter; + D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG LoopFilterDelta; + D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG Quantization; + D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG QuantizationDelta; + D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG CDEF; + UINT QPMapValuesCount; + _Field_size_full_(QPMapValuesCount) INT16 *pRateControlQPMap; + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG CustomSegmentation; + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MAP CustomSegmentsMap; + } D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA; + +typedef struct D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES + { + UINT64 RowCount; + UINT64 ColCount; + UINT64 RowHeights[ 64 ]; + UINT64 ColWidths[ 64 ]; + UINT64 ContextUpdateTileId; + } D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES; + +typedef struct D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES + { + UINT64 CompoundPredictionType; + D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG LoopFilter; + D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG LoopFilterDelta; + D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG Quantization; + D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG QuantizationDelta; + D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG CDEF; + D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG SegmentationConfig; + UINT64 PrimaryRefFrame; + UINT64 ReferenceIndices[ 7 ]; + } D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES; + typedef enum D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE { @@ -6338,7 +6807,9 @@ enum D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE = 0x4, D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_INITIAL_QP = 0x8, D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE = 0x10, - D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES = 0x20 + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES = 0x20, + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT = 0x40, + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED = 0x80 } D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS; DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS); @@ -6349,6 +6820,14 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP UINT ConstantQP_InterPredictedFrame_BiDirectionalRef; } D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP; +typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1 + { + UINT ConstantQP_FullIntracodedFrame; + UINT ConstantQP_InterPredictedFrame_PrevRefOnly; + UINT ConstantQP_InterPredictedFrame_BiDirectionalRef; + UINT QualityVsSpeed; + } D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1; + typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR { UINT InitialQP; @@ -6360,6 +6839,18 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR UINT64 InitialVBVFullness; } D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR; +typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1 + { + UINT InitialQP; + UINT MinQP; + UINT MaxQP; + UINT64 MaxFrameBitSize; + UINT64 TargetBitRate; + UINT64 VBVCapacity; + UINT64 InitialVBVFullness; + UINT QualityVsSpeed; + } D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1; + typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR { UINT InitialQP; @@ -6372,6 +6863,19 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR UINT64 InitialVBVFullness; } D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR; +typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1 + { + UINT InitialQP; + UINT MinQP; + UINT MaxQP; + UINT64 MaxFrameBitSize; + UINT64 TargetAvgBitRate; + UINT64 PeakBitRate; + UINT64 VBVCapacity; + UINT64 InitialVBVFullness; + UINT QualityVsSpeed; + } D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1; + typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR { UINT InitialQP; @@ -6383,6 +6887,25 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR UINT ConstantQualityTarget; } D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR; +typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 + { + UINT InitialQP; + UINT MinQP; + UINT MaxQP; + UINT64 MaxFrameBitSize; + UINT64 TargetAvgBitRate; + UINT64 PeakBitRate; + UINT ConstantQualityTarget; + UINT64 VBVCapacity; + UINT64 InitialVBVFullness; + UINT QualityVsSpeed; + } D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1; + +typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP + { + UINT QualityVsSpeed; + } D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP; + typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS { UINT DataSize; @@ -6392,6 +6915,11 @@ typedef struct D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS const D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *pConfiguration_CBR; const D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *pConfiguration_VBR; const D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *pConfiguration_QVBR; + const D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP1 *pConfiguration_CQP1; + const D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR1 *pConfiguration_CBR1; + const D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1 *pConfiguration_VBR1; + const D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 *pConfiguration_QVBR1; + const D3D12_VIDEO_ENCODER_RATE_CONTROL_ABSOLUTE_QP_MAP *pConfiguration_AbsoluteQPMap; } ; } D3D12_VIDEO_ENCODER_RATE_CONTROL_CONFIGURATION_PARAMS; @@ -6407,7 +6935,8 @@ typedef enum D3D12_VIDEO_ENCODER_CODEC { D3D12_VIDEO_ENCODER_CODEC_H264 = 0, - D3D12_VIDEO_ENCODER_CODEC_HEVC = 1 + D3D12_VIDEO_ENCODER_CODEC_HEVC = 1, + D3D12_VIDEO_ENCODER_CODEC_AV1 = 2 } D3D12_VIDEO_ENCODER_CODEC; typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC @@ -6439,6 +6968,7 @@ typedef struct D3D12_VIDEO_ENCODER_PROFILE_DESC { D3D12_VIDEO_ENCODER_PROFILE_H264 *pH264Profile; D3D12_VIDEO_ENCODER_PROFILE_HEVC *pHEVCProfile; + D3D12_VIDEO_ENCODER_AV1_PROFILE *pAV1Profile; } ; } D3D12_VIDEO_ENCODER_PROFILE_DESC; @@ -6505,6 +7035,7 @@ typedef struct D3D12_VIDEO_ENCODER_LEVEL_SETTING { D3D12_VIDEO_ENCODER_LEVELS_H264 *pH264LevelSetting; D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC *pHEVCLevelSetting; + D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS *pAV1LevelSetting; } ; } D3D12_VIDEO_ENCODER_LEVEL_SETTING; @@ -6591,7 +7122,9 @@ enum D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION = 1, D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED = 2, D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION = 3, - D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME = 4 + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME = 4, + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION = 5, + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_CONFIGURABLE_GRID_PARTITION = 6 } D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE; typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE @@ -6604,6 +7137,58 @@ typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE BOOL IsSupported; } D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE; +typedef +enum D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS + { + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_NONE = 0, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_NOT_SPECIFIED = 0x1, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_CODEC_CONSTRAINT = 0x2, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_HARDWARE_CONSTRAINT = 0x4, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_ROWS_COUNT = 0x8, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_COLS_COUNT = 0x10, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_WIDTH = 0x20, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_AREA = 0x40, + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAG_TOTAL_TILES = 0x80 + } D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS); +typedef struct D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT + { + BOOL Use128SuperBlocks; + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES TilesConfiguration; + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_VALIDATION_FLAGS ValidationFlags; + UINT MinTileRows; + UINT MaxTileRows; + UINT MinTileCols; + UINT MaxTileCols; + UINT MinTileWidth; + UINT MaxTileWidth; + UINT MinTileArea; + UINT MaxTileArea; + UINT TileSizeBytesMinus1; + } D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT; + +typedef struct D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT + { + UINT DataSize; + union + { + D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT *pAV1Support; + } ; + } D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT; + +typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG + { + UINT NodeIndex; + D3D12_VIDEO_ENCODER_CODEC Codec; + D3D12_VIDEO_ENCODER_PROFILE_DESC Profile; + D3D12_VIDEO_ENCODER_LEVEL_SETTING Level; + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE SubregionMode; + D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC FrameResolution; + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT CodecSupport; + BOOL IsSupported; + } D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG; + typedef enum D3D12_VIDEO_ENCODER_HEAP_FLAGS { @@ -6728,6 +7313,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT { D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 *pH264Support; D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC *pHEVCSupport; + D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT *pAV1Support; } ; } D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT; @@ -6765,6 +7351,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT { D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 *pH264Support; D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC *pHEVCSupport; + D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT *pAV1Support; } ; } D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT; @@ -6793,7 +7380,9 @@ enum D3D12_VIDEO_ENCODER_SUPPORT_FLAGS D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_INITIAL_QP_AVAILABLE = 0x200, D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE = 0x400, D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE = 0x800, - D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE = 0x1000 + D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE = 0x1000, + D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_EXTENSION1_SUPPORT = 0x2000, + D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_QUALITY_VS_SPEED_AVAILABLE = 0x4000 } D3D12_VIDEO_ENCODER_SUPPORT_FLAGS; DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_SUPPORT_FLAGS); @@ -6855,6 +7444,7 @@ typedef struct D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION { D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 *pH264Config; D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC *pHEVCConfig; + D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION *pAV1Config; } ; } D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION; @@ -6870,7 +7460,8 @@ enum D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM = 0, D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_FULL_PIXEL = 1, D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_HALF_PIXEL = 2, - D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL = 3 + D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL = 3, + D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_EIGHTH_PIXEL = 4 } D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE; typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS @@ -6893,7 +7484,8 @@ enum D3D12_VIDEO_ENCODER_VALIDATION_FLAGS D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED = 0x80, D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED = 0x100, D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST = 0x200, - D3D12_VIDEO_ENCODER_VALIDATION_FLAG_GOP_STRUCTURE_NOT_SUPPORTED = 0x800 + D3D12_VIDEO_ENCODER_VALIDATION_FLAG_GOP_STRUCTURE_NOT_SUPPORTED = 0x800, + D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_DATA_NOT_SUPPORTED = 0x1000 } D3D12_VIDEO_ENCODER_VALIDATION_FLAGS; DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_VALIDATION_FLAGS); @@ -6920,6 +7512,7 @@ typedef struct D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE { D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 *pH264GroupOfPictures; D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC *pHEVCGroupOfPictures; + D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE *pAV1SequenceStructure; } ; } D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE; @@ -6943,6 +7536,50 @@ typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT _Field_size_full_(ResolutionsListCount) D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS *pResolutionDependentSupport; } D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT; +typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES + { + union + { + UINT MaxBytesPerSlice; + UINT NumberOfCodingUnitsPerSlice; + UINT NumberOfRowsPerSlice; + UINT NumberOfSlicesPerFrame; + } ; + } D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES; + +typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA + { + UINT DataSize; + union + { + const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_H264; + const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_HEVC; + const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *pTilesPartition_AV1; + } ; + } D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA; + +typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 + { + UINT NodeIndex; + D3D12_VIDEO_ENCODER_CODEC Codec; + DXGI_FORMAT InputFormat; + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration; + D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE CodecGopSequence; + D3D12_VIDEO_ENCODER_RATE_CONTROL RateControl; + D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE IntraRefresh; + D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE SubregionFrameEncoding; + UINT ResolutionsListCount; + const D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC *pResolutionList; + UINT MaxReferenceFramesInDPB; + D3D12_VIDEO_ENCODER_VALIDATION_FLAGS ValidationFlags; + D3D12_VIDEO_ENCODER_SUPPORT_FLAGS SupportFlags; + D3D12_VIDEO_ENCODER_PROFILE_DESC SuggestedProfile; + D3D12_VIDEO_ENCODER_LEVEL_SETTING SuggestedLevel; + _Field_size_full_(ResolutionsListCount) D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS *pResolutionDependentSupport; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA SubregionFrameEncodingData; + UINT MaxQualityVsSpeed; + } D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1; + typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS { UINT NodeIndex; @@ -7716,6 +8353,7 @@ typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA { D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 *pH264PicData; D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC *pHEVCPicData; + D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA *pAV1PicData; } ; } D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA; @@ -7754,27 +8392,6 @@ enum D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS } D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS; DEFINE_ENUM_FLAG_OPERATORS(D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS); -typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES - { - union - { - UINT MaxBytesPerSlice; - UINT NumberOfCodingUnitsPerSlice; - UINT NumberOfRowsPerSlice; - UINT NumberOfSlicesPerFrame; - } ; - } D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES; - -typedef struct D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA - { - UINT DataSize; - union - { - const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_H264; - const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *pSlicesPartition_HEVC; - } ; - } D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA; - typedef struct D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC { D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS Flags; diff --git a/thirdparty/directx_headers/d3dcommon.h b/thirdparty/directx_headers/include/directx/d3dcommon.h similarity index 99% rename from thirdparty/directx_headers/d3dcommon.h rename to thirdparty/directx_headers/include/directx/d3dcommon.h index 33e7762374f..974f205a604 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 00000000000..1187816c1e4 --- /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 00000000000..2c2b135a62c --- /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 00000000000..653a422d03b --- /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 + +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 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 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 m_dProtectedResourceSessionSupport; + D3D12_FEATURE_DATA_ROOT_SIGNATURE m_dRootSignature; + std::vector 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 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 m_dProtectedResourceSessionTypeCount; // Cat2 NodeIndex + std::vector 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, 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(0); + } + return result; + } + } + + // Shader model may not be supported. Continue the rest initializations + m_dShaderModel.HighestShaderModel = static_cast(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(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(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(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(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 00000000000..593f7637a32 --- /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 +#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 +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(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(Left); + top = 0; + front = 0; + right = static_cast(Right); + bottom = 1; + back = 1; + } + explicit CD3DX12_BOX( + LONG Left, + LONG Top, + LONG Right, + LONG Bottom ) noexcept + { + left = static_cast(Left); + top = static_cast(Top); + front = 0; + right = static_cast(Right); + bottom = static_cast(Bottom); + back = 1; + } + explicit CD3DX12_BOX( + LONG Left, + LONG Top, + LONG Front, + LONG Right, + LONG Bottom, + LONG Back ) noexcept + { + left = static_cast(Left); + top = static_cast(Top); + front = static_cast(Front); + right = static_cast(Right); + bottom = static_cast(Bottom); + back = static_cast(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(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(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(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(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 00000000000..2b74d70f77e --- /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 00000000000..b94073d38cc --- /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 +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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(Desc.pPipelineStateSubobjectStream)+CurOffset; + auto SubobjectType = *reinterpret_cast(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(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS: + pCallbacks->VSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS: + pCallbacks->PSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS: + pCallbacks->DSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS: + pCallbacks->HSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS: + pCallbacks->GSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS: + pCallbacks->CSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS: + pCallbacks->ASCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS: + pCallbacks->MSCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT: + pCallbacks->StreamOutputCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND: + pCallbacks->BlendStateCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK: + pCallbacks->SampleMaskCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER: + pCallbacks->RasterizerStateCb(*reinterpret_cast(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(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(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM5::RasterizerState); + break; +#endif + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL: + pCallbacks->DepthStencilStateCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1: + pCallbacks->DepthStencilState1Cb(*reinterpret_cast(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(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM3::DepthStencilState); + break; +#endif + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT: + pCallbacks->InputLayoutCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE: + pCallbacks->IBStripCutValueCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY: + pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS: + pCallbacks->RTVFormatsCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT: + pCallbacks->DSVFormatCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC: + pCallbacks->SampleDescCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK: + pCallbacks->NodeMaskCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO: + pCallbacks->CachedPSOCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS: + pCallbacks->FlagsCb(*reinterpret_cast(pStream)); + SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags); + break; + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING: + pCallbacks->ViewInstancingCb(*reinterpret_cast(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 00000000000..301100c034f --- /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 00000000000..fc032f86cda --- /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 00000000000..902ec0cd6ee --- /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 +inline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept +{ + MipSlice = static_cast(Subresource % MipLevels); + ArraySlice = static_cast((Subresource / MipLevels) % ArraySize); + PlaneSlice = static_cast(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(pDest->pData) + pDest->SlicePitch * z; + auto pSrcSlice = static_cast(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(pDest->pData) + pDest->SlicePitch * z; + auto pSrcSlice = (static_cast(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(&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(&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(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(&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(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(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources; + if (MemToAlloc > SIZE_MAX) + { + return 0; + } + void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast(MemToAlloc)); + if (pMem == nullptr) + { + return 0; + } + auto pLayouts = static_cast(pMem); + auto pRowSizesInBytes = reinterpret_cast(pLayouts + NumSubresources); + auto pNumRows = reinterpret_cast(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(&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(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources; + if (MemToAlloc > SIZE_MAX) + { + return 0; + } + void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast(MemToAlloc)); + if (pMem == nullptr) + { + return 0; + } + auto pLayouts = static_cast(pMem); + auto pRowSizesInBytes = reinterpret_cast(pLayouts + NumSubresources); + auto pNumRows = reinterpret_cast(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(&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 +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(&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 +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(&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(LclDesc), static_cast(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(resourceDesc.Width >> MipLevel, WidthAlignment); + const UINT Height = D3DX12AlignAtLeast(resourceDesc.Height >> MipLevel, HeightAlignment); + const UINT16 Depth = D3DX12AlignAtLeast(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(&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 00000000000..572efed8524 --- /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(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(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(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(const_cast(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(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 00000000000..74dc6ca2d9f --- /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 +#include +#include +#include +#ifndef D3DX12_USE_ATL +#include +#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 +#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(m_SubobjectArray[i].pDesc); + D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation; + auto pWrapper = + static_cast(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(*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(); + // 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 + 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 m_SubobjectList; // Pointers to list nodes handed out so + // these can be edited live + std::vector m_SubobjectArray; // Built at the end, copying list contents + + std::list + 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 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> 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 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(m_Exports.size()); + } + template + 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 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(m_Exports.size()); + } + template + 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 m_CollectionRef; + CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings; + std::vector 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 + 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 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 + 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 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 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 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 similarity index 100% rename from thirdparty/directx_headers/dxcore.h rename to 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 similarity index 100% rename from thirdparty/directx_headers/dxcore_interface.h rename to thirdparty/directx_headers/include/directx/dxcore_interface.h diff --git a/thirdparty/directx_headers/dxgicommon.h b/thirdparty/directx_headers/include/directx/dxgicommon.h similarity index 100% rename from thirdparty/directx_headers/dxgicommon.h rename to thirdparty/directx_headers/include/directx/dxgicommon.h diff --git a/thirdparty/directx_headers/dxgiformat.h b/thirdparty/directx_headers/include/directx/dxgiformat.h similarity index 99% rename from thirdparty/directx_headers/dxgiformat.h rename to thirdparty/directx_headers/include/directx/dxgiformat.h index 52aae1b2bed..83e6c077564 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 00000000000..b9a7b08fa7a --- /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 GUID uuidof() = delete; +template GUID uuidof(T*) { return uuidof(); } +template GUID uuidof(T**) { return uuidof(); } +template GUID uuidof(T&) { return uuidof(); } + +// 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(), __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() \ +{ \ + 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() \ +{ \ + 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