From 364f916f3f0141c247e32e63624b063905d66b02 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Sun, 30 Jun 2024 19:30:54 -0300 Subject: [PATCH] Add debug utilities for Vulkan Features: - Debug-only tracking of objects by type. See get_driver_allocs_by_object_type et al. - Debug-only Breadcrumb info for debugging GPU crashes and device lost - Performance report per frame from get_perf_report - Some VMA calls had to be modified in order to insert the necessary memory callbacks Functionality marked as "debug-only" is only available in debug or dev builds. Misc fixes: - Early break optimization in RenderingDevice::uniform_set_create ============================ The work was performed by collaboration of TheForge and Google. I am merely splitting it up into smaller PRs and cleaning it up. --- core/os/memory.cpp | 33 ++ core/os/memory.h | 24 + doc/classes/RenderingDevice.xml | 125 ++++- .../d3d12/rendering_device_driver_d3d12.cpp | 9 + drivers/d3d12/rendering_device_driver_d3d12.h | 6 + drivers/metal/rendering_device_driver_metal.h | 5 + .../metal/rendering_device_driver_metal.mm | 10 + .../rendering_context_driver_vulkan.cpp | 333 +++++++++++- .../vulkan/rendering_context_driver_vulkan.h | 50 ++ .../vulkan/rendering_device_driver_vulkan.cpp | 499 +++++++++++++++--- .../vulkan/rendering_device_driver_vulkan.h | 33 +- .../4.3-stable.expected | 12 + misc/scripts/validate_extension_api.sh | 1 + modules/lightmapper_rd/lightmapper_rd.cpp | 5 +- ...endering_context_driver_vulkan_android.cpp | 2 +- .../rendering_context_driver_vulkan_ios.mm | 2 +- ...endering_context_driver_vulkan_wayland.cpp | 2 +- .../rendering_context_driver_vulkan_x11.cpp | 2 +- .../rendering_context_driver_vulkan_macos.mm | 2 +- ...endering_context_driver_vulkan_windows.cpp | 2 +- .../rendering/renderer_rd/environment/sky.cpp | 2 +- .../forward_mobile/render_forward_mobile.cpp | 13 +- .../renderer_rd/renderer_canvas_render_rd.cpp | 3 +- .../rendering/rendering_context_driver.cpp | 40 ++ servers/rendering/rendering_context_driver.h | 13 + servers/rendering/rendering_device.compat.inc | 11 +- servers/rendering/rendering_device.cpp | 97 +++- servers/rendering/rendering_device.h | 29 +- servers/rendering/rendering_device_commons.h | 38 ++ servers/rendering/rendering_device_driver.h | 6 + servers/rendering/rendering_device_graph.cpp | 11 +- servers/rendering/rendering_device_graph.h | 9 +- 32 files changed, 1321 insertions(+), 108 deletions(-) diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 32c316e58e8c..dae0a31fe021 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -35,6 +35,7 @@ #include #include +#include void *operator new(size_t p_size, const char *p_description) { return Memory::alloc_static(p_size, false); @@ -65,6 +66,38 @@ SafeNumeric Memory::max_usage; SafeNumeric Memory::alloc_count; +inline bool is_power_of_2(size_t x) { return x && ((x & (x - 1U)) == 0U); } + +void *Memory::alloc_aligned_static(size_t p_bytes, size_t p_alignment) { + DEV_ASSERT(is_power_of_2(p_alignment)); + + void *p1, *p2; + if ((p1 = (void *)malloc(p_bytes + p_alignment - 1 + sizeof(uint32_t))) == nullptr) { + return nullptr; + } + + p2 = (void *)(((uintptr_t)p1 + sizeof(uint32_t) + p_alignment - 1) & ~((p_alignment)-1)); + *((uint32_t *)p2 - 1) = (uint32_t)((uintptr_t)p2 - (uintptr_t)p1); + return p2; +} + +void *Memory::realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment) { + if (p_memory == nullptr) { + return alloc_aligned_static(p_bytes, p_alignment); + } + + void *ret = alloc_aligned_static(p_bytes, p_alignment); + memcpy(ret, p_memory, p_prev_bytes); + free_aligned_static(p_memory); + return ret; +} + +void Memory::free_aligned_static(void *p_memory) { + uint32_t offset = *((uint32_t *)p_memory - 1); + void *p = (void *)((uint8_t *)p_memory - offset); + free(p); +} + void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { #ifdef DEBUG_ENABLED bool prepad = true; diff --git a/core/os/memory.h b/core/os/memory.h index d03e08d78586..033e417cb57f 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -62,6 +62,30 @@ class Memory { static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); static void free_static(void *p_ptr, bool p_pad_align = false); + // ↓ return value of alloc_aligned_static + // ┌─────────────────┬─────────┬─────────┬──────────────────┐ + // │ padding (up to │ uint32_t│ void* │ padding (up to │ + // │ p_alignment - 1)│ offset │ p_bytes │ p_alignment - 1) │ + // └─────────────────┴─────────┴─────────┴──────────────────┘ + // + // alloc_aligned_static will allocate p_bytes + p_alignment - 1 + sizeof(uint32_t) and + // then offset the pointer until alignment is satisfied. + // + // This offset is stored before the start of the returned ptr so we can retrieve the original/real + // start of the ptr in order to free it. + // + // The rest is wasted as padding in the beginning and end of the ptr. The sum of padding at + // both start and end of the block must add exactly to p_alignment - 1. + // + // p_alignment MUST be a power of 2. + static void *alloc_aligned_static(size_t p_bytes, size_t p_alignment); + static void *realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment); + // Pass the ptr returned by alloc_aligned_static to free it. + // e.g. + // void *data = realloc_aligned_static( bytes, 16 ); + // free_aligned_static( data ); + static void free_aligned_static(void *p_memory); + static uint64_t get_mem_available(); static uint64_t get_mem_usage(); static uint64_t get_mem_max_usage(); diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 876f229d0c88..96c7d0d4d406 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -218,6 +218,7 @@ + Starts a list of raster drawing commands created with the [code]draw_*[/code] methods. The returned value should be passed to other [code]draw_list_*[/code] functions. Multiple draw lists cannot be created at the same time; you must finish the previous draw list first using [method draw_list_end]. @@ -225,7 +226,7 @@ [codeblock] var rd = RenderingDevice.new() var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)]) - var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors) + var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors, RenderingDevice.OPAQUE_PASS) # Draw opaque. rd.draw_list_bind_render_pipeline(draw_list, raster_pipeline) @@ -240,6 +241,11 @@ rd.draw_list_end() [/codeblock] + The [param breadcrumb] parameter can be an arbitrary 32-bit integer that is useful to diagnose GPU crashes. If Godot is built in dev or debug mode; when the GPU crashes Godot will dump all shaders that were being executed at the time of the crash and the breadcrumb is useful to diagnose what passes did those shaders belong to. + It does not affect rendering behavior and can be set to 0. It is recommended to use [enum BreadcrumbMarker] enumerations for consistency but it's not required. It is also possible to use bitwise operations to add extra data. e.g. + [codeblock] + rd.draw_list_begin(fb[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors, RenderingDevice.OPAQUE_PASS | 5) + [/codeblock] @@ -487,6 +493,31 @@ Returns the index of the last frame rendered that has rendering timestamps available for querying. + + + + Returns how many allocations the GPU has performed for internal driver structures. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + + + + + + Same as [method get_device_allocation_count] but filtered for a given object type. + The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + + + + + + Same as [method get_device_total_memory] but filtered for a given object type. + The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + @@ -499,12 +530,44 @@ Returns the universally unique identifier for the pipeline cache. This is used to cache shader files on disk, which avoids shader recompilations on subsequent engine runs. This UUID varies depending on the graphics card model, but also the driver version. Therefore, updating graphics drivers will invalidate the shader cache. + + + + Returns how much bytes the GPU is using. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + Returns the vendor of the video adapter (e.g. "NVIDIA Corporation"). Equivalent to [method RenderingServer.get_video_adapter_vendor]. See also [method get_device_name]. + + + + Returns how many allocations the GPU driver has performed for internal driver structures. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + + + + + + Same as [method get_driver_allocation_count] but filtered for a given object type. + The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + + + + + + Same as [method get_driver_total_memory] but filtered for a given object type. + The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + @@ -514,6 +577,13 @@ Returns the unique identifier of the driver [param resource] for the specified [param rid]. Some driver resource types ignore the specified [param rid] (see [enum DriverResource] descriptions). [param index] is always ignored but must be specified anyway. + + + + Returns how much bytes the GPU driver is using for internal driver structures. + This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown. + + @@ -527,6 +597,33 @@ Returns the memory usage in bytes corresponding to the given [param type]. When using Vulkan, these statistics are calculated by [url=https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator]Vulkan Memory Allocator[/url]. + + + + Returns a string with a performance report from the past frame. Updates every frame. + + + + + + + Returns the name of the type of object for the given [param type_index]. This value must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns the same string. + The return value is important because it gives meaning to the types passed to [method get_driver_memory_by_object_type], [method get_driver_allocs_by_object_type], [method get_device_memory_by_object_type], and [method get_device_allocs_by_object_type]. Examples of strings it can return (not exhaustive): + - DEVICE_MEMORY + - PIPELINE_CACHE + - SWAPCHAIN_KHR + - COMMAND_POOL + Thus if e.g. [code]get_tracked_object_name(5)[/code] returns "COMMAND_POOL", then [code]get_device_memory_by_object_type(5)[/code] returns the bytes used by the GPU for command pools. + This is only used by Vulkan in Debug builds. + + + + + + Returns how many types of trackable objects are. + This is only used by Vulkan in Debug builds. + + @@ -2362,5 +2459,31 @@ Returned by functions that return a format ID if a value is invalid. + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 38caff648e25..a445006058cd 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -3815,6 +3815,11 @@ void RenderingDeviceDriverD3D12::shader_free(ShaderID p_shader) { VersatileResource::free(resources_allocator, shader_info_in); } +void RenderingDeviceDriverD3D12::shader_destroy_modules(ShaderID p_shader) { + ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id; + shader_info_in->stages_bytecode.clear(); +} + /*********************/ /**** UNIFORM SET ****/ /*********************/ @@ -6036,6 +6041,10 @@ void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer) #endif } +void RenderingDeviceDriverD3D12::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) { + // TODO: Implement via DRED. +} + /********************/ /**** SUBMISSION ****/ /********************/ diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 61b1498755f6..ac0ad41294e4 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -714,6 +714,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { 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; + virtual void shader_destroy_modules(ShaderID p_shader) override final; /*********************/ /**** UNIFORM SET ****/ @@ -945,6 +946,11 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final; virtual void command_end_label(CommandBufferID p_cmd_buffer) override final; + /****************/ + /**** DEBUG *****/ + /****************/ + virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final; + /********************/ /**** SUBMISSION ****/ /********************/ diff --git a/drivers/metal/rendering_device_driver_metal.h b/drivers/metal/rendering_device_driver_metal.h index e7efaff81775..1bb71583ab6c 100644 --- a/drivers/metal/rendering_device_driver_metal.h +++ b/drivers/metal/rendering_device_driver_metal.h @@ -231,6 +231,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public 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; + virtual void shader_destroy_modules(ShaderID p_shader) override final; #pragma mark - Uniform Set @@ -376,6 +377,10 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final; virtual void command_end_label(CommandBufferID p_cmd_buffer) override final; +#pragma mark - Debug + + virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final; + #pragma mark - Submission virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) override final; diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index cde730df9c2c..0a9fde06a73b 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -2447,6 +2447,10 @@ void deserialize(BufReader &p_reader) { delete obj; } +void RenderingDeviceDriverMetal::shader_destroy_modules(ShaderID p_shader) { + // TODO. +} + /*********************/ /**** UNIFORM SET ****/ /*********************/ @@ -3541,6 +3545,12 @@ bool isArrayTexture(MTLTextureType p_type) { [cb->get_command_buffer() popDebugGroup]; } +#pragma mark - Debug + +void RenderingDeviceDriverMetal::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) { + // TODO: Implement. +} + #pragma mark - Submission void RenderingDeviceDriverMetal::begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) { diff --git a/drivers/vulkan/rendering_context_driver_vulkan.cpp b/drivers/vulkan/rendering_context_driver_vulkan.cpp index fe2ff5e0daeb..6ffbb91516fc 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_context_driver_vulkan.cpp @@ -40,21 +40,340 @@ #include "rendering_device_driver_vulkan.h" #include "vulkan_hooks.h" +#if defined(VK_TRACK_DRIVER_MEMORY) +/*************************************************/ +// Driver memory tracking +/*************************************************/ +// Total driver memory and allocation amount. +SafeNumeric driver_memory_total_memory; +SafeNumeric driver_memory_total_alloc_count; +// Amount of driver memory for every object type. +SafeNumeric driver_memory_tracker[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT][RenderingContextDriverVulkan::VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT]; +// Amount of allocations for every object type. +SafeNumeric driver_memory_allocation_count[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT][RenderingContextDriverVulkan::VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT]; +#endif + +#if defined(VK_TRACK_DEVICE_MEMORY) +/*************************************************/ +// Device memory report +/*************************************************/ +// Total device memory and allocation amount. +HashMap memory_report_table; +// Total memory and allocation amount. +SafeNumeric memory_report_total_memory; +SafeNumeric memory_report_total_alloc_count; +// Amount of device memory for every object type. +SafeNumeric memory_report_mem_usage[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT]; +// Amount of device memory allocations for every object type. +SafeNumeric memory_report_allocation_count[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT]; +#endif + +const char *RenderingContextDriverVulkan::get_tracked_object_name(uint32_t p_type_index) const { +#if defined(VK_TRACK_DRIVER_MEMORY) || defined(VK_TRACK_DEVICE_MEMORY) + static constexpr const char *vkTrackedObjectTypeNames[] = { "UNKNOWN", + "INSTANCE", + "PHYSICAL_DEVICE", + "DEVICE", + "QUEUE", + "SEMAPHORE", + "COMMAND_BUFFER", + "FENCE", + "DEVICE_MEMORY", + "BUFFER", + "IMAGE", + "EVENT", + "QUERY_POOL", + "BUFFER_VIEW", + "IMAGE_VIEW", + "SHADER_MODULE", + "PIPELINE_CACHE", + "PIPELINE_LAYOUT", + "RENDER_PASS", + "PIPELINE", + "DESCRIPTOR_SET_LAYOUT", + "SAMPLER", + "DESCRIPTOR_POOL", + "DESCRIPTOR_SET", + "FRAMEBUFFER", + "COMMAND_POOL", + "DESCRIPTOR_UPDATE_TEMPLATE_KHR", + "SURFACE_KHR", + "SWAPCHAIN_KHR", + "DEBUG_UTILS_MESSENGER_EXT", + "DEBUG_REPORT_CALLBACK_EXT", + "ACCELERATION_STRUCTURE", + "VMA_BUFFER_OR_IMAGE" }; + + return vkTrackedObjectTypeNames[p_type_index]; +#else + return "VK_TRACK_DRIVER_* disabled at build time"; +#endif +} + +#if defined(VK_TRACK_DRIVER_MEMORY) || defined(VK_TRACK_DEVICE_MEMORY) +uint64_t RenderingContextDriverVulkan::get_tracked_object_type_count() const { + return VK_TRACKED_OBJECT_TYPE_COUNT; +} +#endif + +#if defined(VK_TRACK_DRIVER_MEMORY) || defined(VK_TRACK_DEVICE_MEMORY) +RenderingContextDriverVulkan::VkTrackedObjectType vk_object_to_tracked_object(VkObjectType p_type) { + if (p_type > VK_OBJECT_TYPE_COMMAND_POOL && p_type != (VkObjectType)RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_VMA) { + switch (p_type) { + case VK_OBJECT_TYPE_SURFACE_KHR: + return RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_SURFACE; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: + return RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_SWAPCHAIN; + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: + return RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: + return RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT; + default: + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Unknown VkObjectType enum value " + itos((uint32_t)p_type) + ".Please add it to VkTrackedObjectType, switch statement in " + "vk_object_to_tracked_object and get_tracked_object_name.", + (int)p_type); + return (RenderingContextDriverVulkan::VkTrackedObjectType)VK_OBJECT_TYPE_UNKNOWN; + } + } + + return (RenderingContextDriverVulkan::VkTrackedObjectType)p_type; +} +#endif + +#if defined(VK_TRACK_DEVICE_MEMORY) +uint64_t RenderingContextDriverVulkan::get_device_total_memory() const { + return memory_report_total_memory.get(); +} + +uint64_t RenderingContextDriverVulkan::get_device_allocation_count() const { + return memory_report_total_alloc_count.get(); +} + +uint64_t RenderingContextDriverVulkan::get_device_memory_by_object_type(uint32_t p_type) const { + return memory_report_mem_usage[p_type].get(); +} + +uint64_t RenderingContextDriverVulkan::get_device_allocs_by_object_type(uint32_t p_type) const { + return memory_report_allocation_count[p_type].get(); +} +#endif + +#if defined(VK_TRACK_DRIVER_MEMORY) +uint64_t RenderingContextDriverVulkan::get_driver_total_memory() const { + return driver_memory_total_memory.get(); +} + +uint64_t RenderingContextDriverVulkan::get_driver_allocation_count() const { + return driver_memory_total_alloc_count.get(); +} + +uint64_t RenderingContextDriverVulkan::get_driver_memory_by_object_type(uint32_t p_type) const { + uint64_t ret = 0; + for (uint32_t i = 0; i < VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT; i++) { + ret += driver_memory_tracker[p_type][i].get(); + } + + return ret; +} + +uint64_t RenderingContextDriverVulkan::get_driver_allocs_by_object_type(uint32_t p_type) const { + uint64_t ret = 0; + for (uint32_t i = 0; i < VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT; i++) { + ret += driver_memory_allocation_count[p_type][i].get(); + } + + return ret; +} +#endif + +#if defined(VK_TRACK_DEVICE_MEMORY) +void RenderingContextDriverVulkan::memory_report_callback(const VkDeviceMemoryReportCallbackDataEXT *p_callback_data, void *p_user_data) { + if (!p_callback_data) { + return; + } + const RenderingContextDriverVulkan::VkTrackedObjectType obj_type = vk_object_to_tracked_object(p_callback_data->objectType); + uint64_t obj_id = p_callback_data->memoryObjectId; + + if (p_callback_data->type == VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT) { + // Realloc, update size + if (memory_report_table.has(obj_id)) { + memory_report_total_memory.sub(memory_report_table[obj_id]); + memory_report_mem_usage[obj_type].sub(memory_report_table[obj_id]); + + memory_report_total_memory.add(p_callback_data->size); + memory_report_mem_usage[obj_type].add(p_callback_data->size); + + memory_report_table[p_callback_data->memoryObjectId] = p_callback_data->size; + } else { + memory_report_table[obj_id] = p_callback_data->size; + + memory_report_total_alloc_count.increment(); + memory_report_allocation_count[obj_type].increment(); + memory_report_mem_usage[obj_type].add(p_callback_data->size); + memory_report_total_memory.add(p_callback_data->size); + } + } else if (p_callback_data->type == VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT) { + if (memory_report_table.has(obj_id)) { + memory_report_total_alloc_count.decrement(); + memory_report_allocation_count[obj_type].decrement(); + memory_report_mem_usage[obj_type].sub(p_callback_data->size); + memory_report_total_memory.sub(p_callback_data->size); + + memory_report_table.remove(memory_report_table.find(obj_id)); + } + } +} +#endif + +VkAllocationCallbacks *RenderingContextDriverVulkan::get_allocation_callbacks(VkObjectType p_type) { +#if !defined(VK_TRACK_DRIVER_MEMORY) + return nullptr; +#else + struct TrackedMemHeader { + size_t size; + VkSystemAllocationScope allocation_scope; + VkTrackedObjectType type; + }; + VkAllocationCallbacks tracking_callbacks = { + // Allocation function + nullptr, + []( + void *p_user_data, + size_t size, + size_t alignment, + VkSystemAllocationScope allocation_scope) -> void * { + static constexpr size_t tracking_data_size = 32; + VkTrackedObjectType type = static_cast(*reinterpret_cast(p_user_data)); + + driver_memory_total_memory.add(size); + driver_memory_total_alloc_count.increment(); + driver_memory_tracker[type][allocation_scope].add(size); + driver_memory_allocation_count[type][allocation_scope].increment(); + + alignment = MAX(alignment, tracking_data_size); + + uint8_t *ret = reinterpret_cast(Memory::alloc_aligned_static(size + alignment, alignment)); + if (ret == nullptr) { + return nullptr; + } + + // Track allocation + TrackedMemHeader *header = reinterpret_cast(ret); + header->size = size; + header->allocation_scope = allocation_scope; + header->type = type; + *reinterpret_cast(ret + alignment - sizeof(size_t)) = alignment; + + // Return first available chunk of memory + return ret + alignment; + }, + + // Reallocation function + []( + void *p_user_data, + void *p_original, + size_t size, + size_t alignment, + VkSystemAllocationScope allocation_scope) -> void * { + if (p_original == nullptr) { + VkObjectType type = static_cast(*reinterpret_cast(p_user_data)); + return get_allocation_callbacks(type)->pfnAllocation(p_user_data, size, alignment, allocation_scope); + } + + uint8_t *mem = reinterpret_cast(p_original); + // Retrieve alignment + alignment = *reinterpret_cast(mem - sizeof(size_t)); + // Retrieve allocation data + TrackedMemHeader *header = reinterpret_cast(mem - alignment); + + // Update allocation size + driver_memory_total_memory.sub(header->size); + driver_memory_total_memory.add(size); + driver_memory_tracker[header->type][header->allocation_scope].sub(header->size); + driver_memory_tracker[header->type][header->allocation_scope].add(size); + + uint8_t *ret = reinterpret_cast(Memory::realloc_aligned_static(header, size + alignment, header->size + alignment, alignment)); + if (ret == nullptr) { + return nullptr; + } + // Update tracker + header = reinterpret_cast(ret); + header->size = size; + return ret + alignment; + }, + + // Free function + []( + void *p_user_data, + void *p_memory) { + if (!p_memory) { + return; + } + + uint8_t *mem = reinterpret_cast(p_memory); + size_t alignment = *reinterpret_cast(mem - sizeof(size_t)); + TrackedMemHeader *header = reinterpret_cast(mem - alignment); + + driver_memory_total_alloc_count.decrement(); + driver_memory_total_memory.sub(header->size); + driver_memory_tracker[header->type][header->allocation_scope].sub(header->size); + driver_memory_allocation_count[header->type][header->allocation_scope].decrement(); + + Memory::free_aligned_static(header); + }, + // Internal allocation / deallocation. We don't track them as they cannot really be controlled or optimized by the programmer. + []( + void *p_user_data, + size_t size, + VkInternalAllocationType allocation_type, + VkSystemAllocationScope allocation_scope) { + }, + []( + void *p_user_data, + size_t size, + VkInternalAllocationType allocation_type, + VkSystemAllocationScope allocation_scope) { + }, + }; + + // Create a callback per object type + static VkAllocationCallbacks object_callbacks[VK_TRACKED_OBJECT_TYPE_COUNT] = {}; + static uint32_t object_user_data[VK_TRACKED_OBJECT_TYPE_COUNT] = {}; + + // Only build the first time + if (!object_callbacks[0].pfnAllocation) { + for (uint32_t c = 0; c < VK_TRACKED_OBJECT_TYPE_COUNT; ++c) { + object_callbacks[c] = tracking_callbacks; + object_user_data[c] = c; + object_callbacks[c].pUserData = &object_user_data[c]; + + for (uint32_t i = 0; i < VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT; i++) { + driver_memory_tracker[c][i].set(0); + driver_memory_allocation_count[c][i].set(0); + } + } + } + + uint32_t type_index = vk_object_to_tracked_object(p_type); + return &object_callbacks[type_index]; +#endif +} + RenderingContextDriverVulkan::RenderingContextDriverVulkan() { // Empty constructor. } RenderingContextDriverVulkan::~RenderingContextDriverVulkan() { if (debug_messenger != VK_NULL_HANDLE && functions.DestroyDebugUtilsMessengerEXT != nullptr) { - functions.DestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr); + functions.DestroyDebugUtilsMessengerEXT(instance, debug_messenger, get_allocation_callbacks(VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT)); } if (debug_report != VK_NULL_HANDLE && functions.DestroyDebugReportCallbackEXT != nullptr) { - functions.DestroyDebugReportCallbackEXT(instance, debug_report, nullptr); + functions.DestroyDebugReportCallbackEXT(instance, debug_report, get_allocation_callbacks(VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT)); } if (instance != VK_NULL_HANDLE) { - vkDestroyInstance(instance, nullptr); + vkDestroyInstance(instance, get_allocation_callbacks(VK_OBJECT_TYPE_INSTANCE)); } } @@ -441,7 +760,7 @@ Error RenderingContextDriverVulkan::_initialize_instance() { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_utils\nGetProcAddr: Failure"); } - VkResult res = functions.CreateDebugUtilsMessengerEXT(instance, &debug_messenger_create_info, nullptr, &debug_messenger); + VkResult res = functions.CreateDebugUtilsMessengerEXT(instance, &debug_messenger_create_info, get_allocation_callbacks(VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT), &debug_messenger); switch (res) { case VK_SUCCESS: break; @@ -461,7 +780,7 @@ Error RenderingContextDriverVulkan::_initialize_instance() { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_report\nGetProcAddr: Failure"); } - VkResult res = functions.CreateDebugReportCallbackEXT(instance, &debug_report_callback_create_info, nullptr, &debug_report); + VkResult res = functions.CreateDebugReportCallbackEXT(instance, &debug_report_callback_create_info, get_allocation_callbacks(VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT), &debug_report); switch (res) { case VK_SUCCESS: break; @@ -560,7 +879,7 @@ Error RenderingContextDriverVulkan::_create_vulkan_instance(const VkInstanceCrea if (VulkanHooks::get_singleton() != nullptr) { return VulkanHooks::get_singleton()->create_vulkan_instance(p_create_info, r_instance) ? OK : ERR_CANT_CREATE; } else { - VkResult err = vkCreateInstance(p_create_info, nullptr, r_instance); + VkResult err = vkCreateInstance(p_create_info, get_allocation_callbacks(VK_OBJECT_TYPE_INSTANCE), r_instance); ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE, "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" "vkCreateInstance Failure"); @@ -679,7 +998,7 @@ bool RenderingContextDriverVulkan::surface_get_needs_resize(SurfaceID p_surface) void RenderingContextDriverVulkan::surface_destroy(SurfaceID p_surface) { Surface *surface = (Surface *)(p_surface); - vkDestroySurfaceKHR(instance, surface->vk_surface, nullptr); + vkDestroySurfaceKHR(instance, surface->vk_surface, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR)); memdelete(surface); } diff --git a/drivers/vulkan/rendering_context_driver_vulkan.h b/drivers/vulkan/rendering_context_driver_vulkan.h index f1d4021e3225..e70d17e13159 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.h +++ b/drivers/vulkan/rendering_context_driver_vulkan.h @@ -35,6 +35,11 @@ #include "servers/rendering/rendering_context_driver.h" +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) +#define VK_TRACK_DRIVER_MEMORY +#define VK_TRACK_DEVICE_MEMORY +#endif + #ifdef USE_VOLK #include #else @@ -77,6 +82,12 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr; + // Debug marker extensions. + PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT = nullptr; + PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT = nullptr; + PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT = nullptr; + PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT = nullptr; + bool debug_report_functions_available() const { return CreateDebugReportCallbackEXT != nullptr && DebugReportMessageEXT != nullptr && @@ -110,6 +121,8 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { // Static callbacks. static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data); static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(VkDebugReportFlagsEXT p_flags, VkDebugReportObjectTypeEXT p_object_type, uint64_t p_object, size_t p_location, int32_t p_message_code, const char *p_layer_prefix, const char *p_message, void *p_user_data); + // Debug marker extensions. + VkDebugReportObjectTypeEXT _convert_to_debug_report_objectType(VkObjectType p_object_type); protected: Error _find_validation_layers(TightLocalVector &r_layer_names) const; @@ -153,6 +166,43 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { bool queue_family_supports_present(VkPhysicalDevice p_physical_device, uint32_t p_queue_family_index, SurfaceID p_surface) const; const Functions &functions_get() const; + static VkAllocationCallbacks *get_allocation_callbacks(VkObjectType p_type); + +#if defined(VK_TRACK_DRIVER_MEMORY) || defined(VK_TRACK_DEVICE_MEMORY) + enum VkTrackedObjectType{ + VK_TRACKED_OBJECT_TYPE_SURFACE = VK_OBJECT_TYPE_COMMAND_POOL + 1, + VK_TRACKED_OBJECT_TYPE_SWAPCHAIN, + VK_TRACKED_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, + VK_TRACKED_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT, + VK_TRACKED_OBJECT_TYPE_VMA, + VK_TRACKED_OBJECT_TYPE_COUNT + }; + + enum VkTrackedSystemAllocationScope{ + VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE + 1 + }; +#endif + + const char *get_tracked_object_name(uint32_t p_type_index) const override; +#if defined(VK_TRACK_DRIVER_MEMORY) || defined(VK_TRACK_DEVICE_MEMORY) + uint64_t get_tracked_object_type_count() const override; +#endif + +#if defined(VK_TRACK_DRIVER_MEMORY) + uint64_t get_driver_total_memory() const override; + uint64_t get_driver_allocation_count() const override; + uint64_t get_driver_memory_by_object_type(uint32_t p_type) const override; + uint64_t get_driver_allocs_by_object_type(uint32_t p_type) const override; +#endif + +#if defined(VK_TRACK_DEVICE_MEMORY) + uint64_t get_device_total_memory() const override; + uint64_t get_device_allocation_count() const override; + uint64_t get_device_memory_by_object_type(uint32_t p_type) const override; + uint64_t get_device_allocs_by_object_type(uint32_t p_type) const override; + static VKAPI_ATTR void VKAPI_CALL memory_report_callback(const VkDeviceMemoryReportCallbackDataEXT *p_callback_data, void *p_user_data); +#endif + RenderingContextDriverVulkan(); virtual ~RenderingContextDriverVulkan() override; }; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 97fd156584cc..092af13b213b 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -502,6 +502,24 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { _register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true); } +#if defined(VK_TRACK_DEVICE_MEMORY) + _register_requested_device_extension(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, false); +#endif + _register_requested_device_extension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, false); + + { + // Debug marker extensions. + // Should be last element in the array. +#ifdef DEV_ENABLED + bool want_debug_markers = true; +#else + bool want_debug_markers = OS::get_singleton()->is_stdout_verbose(); +#endif + if (want_debug_markers) { + _register_requested_device_extension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME, false); + } + } + uint32_t device_extension_count = 0; VkResult err = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &device_extension_count, nullptr); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); @@ -745,6 +763,15 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() { if (enabled_device_extension_names.has(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) { pipeline_cache_control_support = pipeline_cache_control_features.pipelineCreationCacheControl; } + + if (enabled_device_extension_names.has(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) { + device_fault_support = true; + } +#if defined(VK_TRACK_DEVICE_MEMORY) + if (enabled_device_extension_names.has(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME)) { + device_memory_report_support = true; + } +#endif } if (functions.GetPhysicalDeviceProperties2 != nullptr) { @@ -913,6 +940,26 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVectorcreate_vulkan_device(&create_info, &vk_device); ERR_FAIL_COND_V(!device_created, ERR_CANT_CREATE); } else { - VkResult err = vkCreateDevice(physical_device, &create_info, nullptr, &vk_device); + VkResult err = vkCreateDevice(physical_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DEVICE), &vk_device); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); } @@ -989,6 +1036,19 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVectorimage_semaphores[p_semaphore_index], nullptr); + vkDestroySemaphore(vk_device, p_command_queue->image_semaphores[p_semaphore_index], VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); p_command_queue->image_semaphores[p_semaphore_index] = semaphore; p_command_queue->free_image_semaphores.push_back(p_semaphore_index); return true; } +// Debug marker extensions. +VkDebugReportObjectTypeEXT RenderingDeviceDriverVulkan::_convert_to_debug_report_objectType(VkObjectType p_object_type) { + switch (p_object_type) { + case VK_OBJECT_TYPE_UNKNOWN: + return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; + case VK_OBJECT_TYPE_INSTANCE: + return VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT; + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: + return VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT; + case VK_OBJECT_TYPE_DEVICE: + return VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT; + case VK_OBJECT_TYPE_QUEUE: + return VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT; + case VK_OBJECT_TYPE_SEMAPHORE: + return VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT; + case VK_OBJECT_TYPE_COMMAND_BUFFER: + return VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT; + case VK_OBJECT_TYPE_FENCE: + return VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT; + case VK_OBJECT_TYPE_DEVICE_MEMORY: + return VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT; + case VK_OBJECT_TYPE_BUFFER: + return VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT; + case VK_OBJECT_TYPE_IMAGE: + return VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT; + case VK_OBJECT_TYPE_EVENT: + return VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT; + case VK_OBJECT_TYPE_QUERY_POOL: + return VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT; + case VK_OBJECT_TYPE_BUFFER_VIEW: + return VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT; + case VK_OBJECT_TYPE_IMAGE_VIEW: + return VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT; + case VK_OBJECT_TYPE_SHADER_MODULE: + return VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT; + case VK_OBJECT_TYPE_PIPELINE_CACHE: + return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT; + case VK_OBJECT_TYPE_PIPELINE_LAYOUT: + return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT; + case VK_OBJECT_TYPE_RENDER_PASS: + return VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT; + case VK_OBJECT_TYPE_PIPELINE: + return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT; + case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: + return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT; + case VK_OBJECT_TYPE_SAMPLER: + return VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT; + case VK_OBJECT_TYPE_DESCRIPTOR_POOL: + return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT; + case VK_OBJECT_TYPE_DESCRIPTOR_SET: + return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT; + case VK_OBJECT_TYPE_FRAMEBUFFER: + return VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT; + case VK_OBJECT_TYPE_COMMAND_POOL: + return VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT; + case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: + return VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT; + case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: + return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT; + case VK_OBJECT_TYPE_SURFACE_KHR: + return VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: + return VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT; + case VK_OBJECT_TYPE_DISPLAY_KHR: + return VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT; + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: + return VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: + return VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT; + case VK_OBJECT_TYPE_CU_MODULE_NVX: + return VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT; + case VK_OBJECT_TYPE_CU_FUNCTION_NVX: + return VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR: + return VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT; + case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: + return VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: + return VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT; + default: + break; + } + + return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; +} void RenderingDeviceDriverVulkan::_set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) { const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); @@ -1171,6 +1316,16 @@ void RenderingDeviceDriverVulkan::_set_object_name(VkObjectType p_object_type, u name_info.objectHandle = p_object_handle; name_info.pObjectName = obj_data.get_data(); functions.SetDebugUtilsObjectNameEXT(vk_device, &name_info); + } else if (functions.DebugMarkerSetObjectNameEXT != nullptr) { + // Debug marker extensions. + CharString obj_data = p_object_name.utf8(); + VkDebugMarkerObjectNameInfoEXT name_info; + name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + name_info.pNext = nullptr; + name_info.objectType = _convert_to_debug_report_objectType(p_object_type); + name_info.object = p_object_handle; + name_info.pObjectName = obj_data.get_data(); + functions.DebugMarkerSetObjectNameEXT(vk_device, &name_info); } } @@ -1211,6 +1366,7 @@ Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t ERR_FAIL_COND_V(err != OK, err); max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool"); + breadcrumb_buffer = buffer_create(sizeof(uint32_t), BufferUsageBits::BUFFER_USAGE_TRANSFER_TO_BIT, MemoryAllocationType::MEMORY_ALLOCATION_TYPE_CPU); return OK; } @@ -1279,11 +1435,10 @@ RDD::BufferID RenderingDeviceDriverVulkan::buffer_create(uint64_t p_size, BitFie // 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; + alloc_create_info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; if (p_size <= SMALL_ALLOCATION_MAX_SIZE) { uint32_t mem_type_index = 0; vmaFindMemoryTypeIndexForBufferInfo(allocator, &create_info, &alloc_create_info, &mem_type_index); @@ -1295,11 +1450,15 @@ RDD::BufferID RenderingDeviceDriverVulkan::buffer_create(uint64_t p_size, BitFie 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); + + VkResult err = vkCreateBuffer(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_BUFFER), &vk_buffer); ERR_FAIL_COND_V_MSG(err, BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + "."); + err = vmaAllocateMemoryForBuffer(allocator, vk_buffer, &alloc_create_info, &allocation, &alloc_info); + ERR_FAIL_COND_V_MSG(err, BufferID(), "Can't allocate memory for buffer of size: " + itos(p_size) + ", error " + itos(err) + "."); + err = vmaBindBufferMemory2(allocator, allocation, 0, vk_buffer, NULL); + ERR_FAIL_COND_V_MSG(err, BufferID(), "Can't bind memory to 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; @@ -1320,7 +1479,7 @@ bool RenderingDeviceDriverVulkan::buffer_set_texel_format(BufferID p_buffer, Dat 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); + VkResult res = vkCreateBufferView(vk_device, &view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_BUFFER_VIEW), &buf_info->vk_view); ERR_FAIL_COND_V_MSG(res, false, "Unable to create buffer view, error " + itos(res) + "."); return true; @@ -1329,9 +1488,12 @@ bool RenderingDeviceDriverVulkan::buffer_set_texel_format(BufferID p_buffer, Dat 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); + vkDestroyBufferView(vk_device, buf_info->vk_view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_BUFFER_VIEW)); } - vmaDestroyBuffer(allocator, buf_info->vk_buffer, buf_info->allocation.handle); + + vkDestroyBuffer(vk_device, buf_info->vk_buffer, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_BUFFER)); + vmaFreeMemory(allocator, buf_info->allocation.handle); + VersatileResource::free(resources_allocator, buf_info); } @@ -1502,7 +1664,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat & 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; + alloc_create_info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; if (image_size <= SMALL_ALLOCATION_MAX_SIZE) { uint32_t mem_type_index = 0; vmaFindMemoryTypeIndexForImageInfo(allocator, &create_info, &alloc_create_info, &mem_type_index); @@ -1514,8 +1676,13 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat & 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) + "."); + + VkResult err = vkCreateImage(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE), &vk_image); + ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImage failed with error " + itos(err) + "."); + err = vmaAllocateMemoryForImage(allocator, vk_image, &alloc_create_info, &allocation, &alloc_info); + ERR_FAIL_COND_V_MSG(err, TextureID(), "Can't allocate memory for image, error: " + itos(err) + "."); + err = vmaBindImageMemory2(allocator, allocation, 0, vk_image, NULL); + ERR_FAIL_COND_V_MSG(err, TextureID(), "Can't bind memory to image, error: " + itos(err) + "."); // Create view. @@ -1537,15 +1704,17 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat & } VkImageView vk_image_view = VK_NULL_HANDLE; - err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &vk_image_view); + err = vkCreateImageView(vk_device, &image_view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &vk_image_view); if (err) { - vmaDestroyImage(allocator, vk_image, allocation); + vkDestroyImage(vk_device, vk_image, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE)); + vmaFreeMemory(allocator, 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_image = vk_image; tex_info->vk_view = vk_image_view; tex_info->rd_format = p_format.format; tex_info->vk_create_info = create_info; @@ -1579,7 +1748,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_from_extension(uint64 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); + VkResult err = vkCreateImageView(vk_device, &image_view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &vk_image_view); if (err) { ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + "."); } @@ -1634,7 +1803,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_or } VkImageView new_vk_image_view = VK_NULL_HANDLE; - VkResult err = vkCreateImageView(vk_device, &image_view_create_info, nullptr, &new_vk_image_view); + VkResult err = vkCreateImageView(vk_device, &image_view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &new_vk_image_view); ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + "."); // Bookkeep. @@ -1687,7 +1856,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(Tex 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); + VkResult err = vkCreateImageView(vk_device, &image_view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &new_vk_image_view); ERR_FAIL_COND_V_MSG(err, TextureID(), "vkCreateImageView failed with error " + itos(err) + "."); // Bookkeep. @@ -1707,9 +1876,10 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(Tex void RenderingDeviceDriverVulkan::texture_free(TextureID p_texture) { TextureInfo *tex_info = (TextureInfo *)p_texture.id; - vkDestroyImageView(vk_device, tex_info->vk_view, nullptr); + vkDestroyImageView(vk_device, tex_info->vk_view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW)); if (tex_info->allocation.handle) { - vmaDestroyImage(allocator, tex_info->vk_view_create_info.image, tex_info->allocation.handle); + vkDestroyImage(vk_device, tex_info->vk_image, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_BUFFER)); + vmaFreeMemory(allocator, tex_info->allocation.handle); } VersatileResource::free(resources_allocator, tex_info); } @@ -1788,7 +1958,7 @@ uint8_t *RenderingDeviceDriverVulkan::texture_map(TextureID p_texture, const Tex void RenderingDeviceDriverVulkan::texture_unmap(TextureID p_texture) { const TextureInfo *tex_info = (const TextureInfo *)p_texture.id; - vkUnmapMemory(vk_device, tex_info->allocation.info.deviceMemory); + vmaUnmapMemory(allocator, tex_info->allocation.handle); } BitField RenderingDeviceDriverVulkan::texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) { @@ -1869,14 +2039,14 @@ RDD::SamplerID RenderingDeviceDriverVulkan::sampler_create(const SamplerState &p 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); + VkResult res = vkCreateSampler(vk_device, &sampler_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SAMPLER), &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); + vkDestroySampler(vk_device, (VkSampler)p_sampler.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SAMPLER)); } bool RenderingDeviceDriverVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) { @@ -2051,7 +2221,7 @@ RDD::FenceID RenderingDeviceDriverVulkan::fence_create() { VkFence vk_fence = VK_NULL_HANDLE; VkFenceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - VkResult err = vkCreateFence(vk_device, &create_info, nullptr, &vk_fence); + VkResult err = vkCreateFence(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FENCE), &vk_fence); ERR_FAIL_COND_V(err != VK_SUCCESS, FenceID()); Fence *fence = memnew(Fence); @@ -2062,10 +2232,13 @@ RDD::FenceID RenderingDeviceDriverVulkan::fence_create() { Error RenderingDeviceDriverVulkan::fence_wait(FenceID p_fence) { Fence *fence = (Fence *)(p_fence.id); - VkResult err = vkWaitForFences(vk_device, 1, &fence->vk_fence, VK_TRUE, UINT64_MAX); - ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + VkResult fence_status = vkGetFenceStatus(vk_device, fence->vk_fence); + if (fence_status == VK_NOT_READY) { + VkResult err = vkWaitForFences(vk_device, 1, &fence->vk_fence, VK_TRUE, UINT64_MAX); + ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + } - err = vkResetFences(vk_device, 1, &fence->vk_fence); + VkResult err = vkResetFences(vk_device, 1, &fence->vk_fence); ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); if (fence->queue_signaled_from != nullptr) { @@ -2090,7 +2263,7 @@ Error RenderingDeviceDriverVulkan::fence_wait(FenceID p_fence) { void RenderingDeviceDriverVulkan::fence_free(FenceID p_fence) { Fence *fence = (Fence *)(p_fence.id); - vkDestroyFence(vk_device, fence->vk_fence, nullptr); + vkDestroyFence(vk_device, fence->vk_fence, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FENCE)); memdelete(fence); } @@ -2102,14 +2275,14 @@ RDD::SemaphoreID RenderingDeviceDriverVulkan::semaphore_create() { VkSemaphore semaphore = VK_NULL_HANDLE; VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - VkResult err = vkCreateSemaphore(vk_device, &create_info, nullptr, &semaphore); + VkResult err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); ERR_FAIL_COND_V(err != VK_SUCCESS, SemaphoreID()); return SemaphoreID(semaphore); } void RenderingDeviceDriverVulkan::semaphore_free(SemaphoreID p_semaphore) { - vkDestroySemaphore(vk_device, VkSemaphore(p_semaphore.id), nullptr); + vkDestroySemaphore(vk_device, VkSemaphore(p_semaphore.id), VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); } /******************/ @@ -2236,7 +2409,7 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; for (uint32_t i = 0; i < frame_count; i++) { - err = vkCreateSemaphore(vk_device, &create_info, nullptr, &semaphore); + err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); command_queue->present_semaphores.push_back(semaphore); } @@ -2263,6 +2436,11 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu device_queue.submit_mutex.lock(); err = vkQueueSubmit(device_queue.queue, 1, &submit_info, vk_fence); device_queue.submit_mutex.unlock(); + + if (err == VK_ERROR_DEVICE_LOST) { + print_lost_device_info(); + CRASH_NOW_MSG("Vulkan device was lost."); + } ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) { @@ -2354,12 +2532,12 @@ void RenderingDeviceDriverVulkan::command_queue_free(CommandQueueID p_cmd_queue) // Erase all the semaphores used for presentation. for (VkSemaphore semaphore : command_queue->present_semaphores) { - vkDestroySemaphore(vk_device, semaphore, nullptr); + vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); } // Erase all the semaphores used for image acquisition. for (VkSemaphore semaphore : command_queue->image_semaphores) { - vkDestroySemaphore(vk_device, semaphore, nullptr); + vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); } // Retrieve the queue family corresponding to the virtual queue. @@ -2387,7 +2565,7 @@ RDD::CommandPoolID RenderingDeviceDriverVulkan::command_pool_create(CommandQueue cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VkCommandPool vk_command_pool = VK_NULL_HANDLE; - VkResult res = vkCreateCommandPool(vk_device, &cmd_pool_info, nullptr, &vk_command_pool); + VkResult res = vkCreateCommandPool(vk_device, &cmd_pool_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_COMMAND_POOL), &vk_command_pool); ERR_FAIL_COND_V_MSG(res, CommandPoolID(), "vkCreateCommandPool failed with error " + itos(res) + "."); CommandPool *command_pool = memnew(CommandPool); @@ -2400,7 +2578,7 @@ void RenderingDeviceDriverVulkan::command_pool_free(CommandPoolID p_cmd_pool) { DEV_ASSERT(p_cmd_pool); CommandPool *command_pool = (CommandPool *)(p_cmd_pool.id); - vkDestroyCommandPool(vk_device, command_pool->vk_command_pool, nullptr); + vkDestroyCommandPool(vk_device, command_pool->vk_command_pool, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_COMMAND_POOL)); memdelete(command_pool); } @@ -2480,7 +2658,7 @@ void RenderingDeviceDriverVulkan::_swap_chain_release(SwapChain *swap_chain) { } for (VkImageView view : swap_chain->image_views) { - vkDestroyImageView(vk_device, view, nullptr); + vkDestroyImageView(vk_device, view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW)); } swap_chain->image_index = UINT_MAX; @@ -2489,7 +2667,7 @@ void RenderingDeviceDriverVulkan::_swap_chain_release(SwapChain *swap_chain) { swap_chain->framebuffers.clear(); if (swap_chain->vk_swapchain != VK_NULL_HANDLE) { - device_functions.DestroySwapchainKHR(vk_device, swap_chain->vk_swapchain, nullptr); + device_functions.DestroySwapchainKHR(vk_device, swap_chain->vk_swapchain, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR)); swap_chain->vk_swapchain = VK_NULL_HANDLE; } @@ -2571,7 +2749,7 @@ RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_creat pass_info.pSubpasses = &subpass; VkRenderPass render_pass = VK_NULL_HANDLE; - err = _create_render_pass(vk_device, &pass_info, nullptr, &render_pass); + err = _create_render_pass(vk_device, &pass_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_RENDER_PASS), &render_pass); ERR_FAIL_COND_V(err != VK_SUCCESS, SwapChainID()); SwapChain *swap_chain = memnew(SwapChain); @@ -2714,7 +2892,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, swap_create_info.compositeAlpha = composite_alpha; swap_create_info.presentMode = present_mode; swap_create_info.clipped = true; - err = device_functions.CreateSwapchainKHR(vk_device, &swap_create_info, nullptr, &swap_chain->vk_swapchain); + err = device_functions.CreateSwapchainKHR(vk_device, &swap_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR), &swap_chain->vk_swapchain); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); uint32_t image_count = 0; @@ -2742,7 +2920,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, VkImageView image_view; for (uint32_t i = 0; i < image_count; i++) { view_create_info.image = swap_chain->images[i]; - err = vkCreateImageView(vk_device, &view_create_info, nullptr, &image_view); + err = vkCreateImageView(vk_device, &view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &image_view); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); swap_chain->image_views.push_back(image_view); @@ -2761,7 +2939,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, VkFramebuffer framebuffer; for (uint32_t i = 0; i < image_count; i++) { fb_create_info.pAttachments = &swap_chain->image_views[i]; - err = vkCreateFramebuffer(vk_device, &fb_create_info, nullptr, &framebuffer); + err = vkCreateFramebuffer(vk_device, &fb_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &framebuffer); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); swap_chain->framebuffers.push_back(RDD::FramebufferID(framebuffer)); @@ -2792,7 +2970,7 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(C // Add a new semaphore if none are free. VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(vk_device, &create_info, nullptr, &semaphore); + err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); ERR_FAIL_COND_V(err != VK_SUCCESS, FramebufferID()); semaphore_index = command_queue->image_semaphores.size(); @@ -2864,7 +3042,7 @@ void RenderingDeviceDriverVulkan::swap_chain_free(SwapChainID p_swap_chain) { _swap_chain_release(swap_chain); if (swap_chain->render_pass.id != 0) { - vkDestroyRenderPass(vk_device, VkRenderPass(swap_chain->render_pass.id), nullptr); + vkDestroyRenderPass(vk_device, VkRenderPass(swap_chain->render_pass.id), VKC::get_allocation_callbacks(VK_OBJECT_TYPE_RENDER_PASS)); } memdelete(swap_chain); @@ -2890,7 +3068,7 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID framebuffer_create_info.layers = 1; VkFramebuffer vk_framebuffer = VK_NULL_HANDLE; - VkResult err = vkCreateFramebuffer(vk_device, &framebuffer_create_info, nullptr, &vk_framebuffer); + VkResult err = vkCreateFramebuffer(vk_device, &framebuffer_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &vk_framebuffer); ERR_FAIL_COND_V_MSG(err, FramebufferID(), "vkCreateFramebuffer failed with error " + itos(err) + "."); #if PRINT_NATIVE_COMMANDS @@ -2905,7 +3083,7 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID } void RenderingDeviceDriverVulkan::framebuffer_free(FramebufferID p_framebuffer) { - vkDestroyFramebuffer(vk_device, (VkFramebuffer)p_framebuffer.id, nullptr); + vkDestroyFramebuffer(vk_device, (VkFramebuffer)p_framebuffer.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER)); } /****************/ @@ -3282,7 +3460,7 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec shader_module_create_info.pCode = (const uint32_t *)stages_spirv[i].ptr(); VkShaderModule vk_module = VK_NULL_HANDLE; - VkResult res = vkCreateShaderModule(vk_device, &shader_module_create_info, nullptr, &vk_module); + VkResult res = vkCreateShaderModule(vk_device, &shader_module_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SHADER_MODULE), &vk_module); if (res) { error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(SHADER_STAGE_NAMES[r_shader_desc.stages[i]]); break; @@ -3309,7 +3487,7 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec layout_create_info.pBindings = vk_set_bindings[i].ptr(); VkDescriptorSetLayout layout = VK_NULL_HANDLE; - VkResult res = vkCreateDescriptorSetLayout(vk_device, &layout_create_info, nullptr, &layout); + VkResult res = vkCreateDescriptorSetLayout(vk_device, &layout_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT), &layout); if (res) { error_text = "Error (" + itos(res) + ") creating descriptor set layout for set " + itos(i); break; @@ -3336,7 +3514,7 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec pipeline_layout_create_info.pPushConstantRanges = push_constant_range; } - VkResult err = vkCreatePipelineLayout(vk_device, &pipeline_layout_create_info, nullptr, &shader_info.vk_pipeline_layout); + VkResult err = vkCreatePipelineLayout(vk_device, &pipeline_layout_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE_LAYOUT), &shader_info.vk_pipeline_layout); if (err) { error_text = "Error (" + itos(err) + ") creating pipeline layout."; } @@ -3345,10 +3523,10 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_bytecode(const Vec 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); + vkDestroyShaderModule(vk_device, shader_info.vk_stages_create_info[i].module, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SHADER_MODULE)); } for (uint32_t i = 0; i < binary_data.set_count; i++) { - vkDestroyDescriptorSetLayout(vk_device, shader_info.vk_descriptor_set_layouts[i], nullptr); + vkDestroyDescriptorSetLayout(vk_device, shader_info.vk_descriptor_set_layouts[i], VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT)); } ERR_FAIL_V_MSG(ShaderID(), error_text); @@ -3365,18 +3543,29 @@ 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); + vkDestroyDescriptorSetLayout(vk_device, shader_info->vk_descriptor_set_layouts[i], VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT)); } - vkDestroyPipelineLayout(vk_device, shader_info->vk_pipeline_layout, nullptr); + vkDestroyPipelineLayout(vk_device, shader_info->vk_pipeline_layout, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE_LAYOUT)); - 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); - } + shader_destroy_modules(p_shader); VersatileResource::free(resources_allocator, shader_info); } +void RenderingDeviceDriverVulkan::shader_destroy_modules(ShaderID p_shader) { + ShaderInfo *si = (ShaderInfo *)p_shader.id; + + for (uint32_t i = 0; i < si->vk_stages_create_info.size(); i++) { + if (si->vk_stages_create_info[i].module) { + vkDestroyShaderModule(vk_device, si->vk_stages_create_info[i].module, + VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SHADER_MODULE)); + si->vk_stages_create_info[i].module = VK_NULL_HANDLE; + } + } + si->vk_stages_create_info.clear(); +} + /*********************/ /**** UNIFORM SET ****/ /*********************/ @@ -3474,7 +3663,7 @@ VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_find_or_creat 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); + VkResult res = vkCreateDescriptorPool(vk_device, &descriptor_set_pool_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_POOL), &vk_pool); if (res) { ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateDescriptorPool failed with error " + itos(res) + "."); } @@ -3494,7 +3683,7 @@ void RenderingDeviceDriverVulkan::_descriptor_set_pool_unreference(DescriptorSet 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); + vkDestroyDescriptorPool(vk_device, p_vk_descriptor_pool, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_POOL)); 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); @@ -3839,7 +4028,7 @@ void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID /******************/ void RenderingDeviceDriverVulkan::pipeline_free(PipelineID p_pipeline) { - vkDestroyPipeline(vk_device, (VkPipeline)p_pipeline.id, nullptr); + vkDestroyPipeline(vk_device, (VkPipeline)p_pipeline.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE)); } // ----- BINDING ----- @@ -3904,7 +4093,7 @@ bool RenderingDeviceDriverVulkan::pipeline_cache_create(const Vector &p cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; } - VkResult err = vkCreatePipelineCache(vk_device, &cache_info, nullptr, &pipelines_cache.vk_cache); + VkResult err = vkCreatePipelineCache(vk_device, &cache_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE_CACHE), &pipelines_cache.vk_cache); if (err != VK_SUCCESS) { WARN_PRINT("vkCreatePipelinecache failed with error " + itos(err) + "."); return false; @@ -3917,7 +4106,7 @@ bool RenderingDeviceDriverVulkan::pipeline_cache_create(const Vector &p void RenderingDeviceDriverVulkan::pipeline_cache_free() { DEV_ASSERT(pipelines_cache.vk_cache); - vkDestroyPipelineCache(vk_device, pipelines_cache.vk_cache, nullptr); + vkDestroyPipelineCache(vk_device, pipelines_cache.vk_cache, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE_CACHE)); pipelines_cache.vk_cache = VK_NULL_HANDLE; DEV_ASSERT(caching_instance_count > 0); @@ -4101,14 +4290,14 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorViewvk_stages_create_info.size(); + ERR_FAIL_COND_V_MSG(pipeline_create_info.stageCount == 0, PipelineID(), + "Cannot create pipeline without shader module, please make sure shader modules are destroyed only after all associated pipelines are created."); 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++) { @@ -4592,7 +4783,7 @@ RDD::PipelineID RenderingDeviceDriverVulkan::render_pipeline_create( // --- VkPipeline vk_pipeline = VK_NULL_HANDLE; - VkResult err = vkCreateGraphicsPipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, nullptr, &vk_pipeline); + VkResult err = vkCreateGraphicsPipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE), &vk_pipeline); ERR_FAIL_COND_V_MSG(err, PipelineID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + "."); return PipelineID(vk_pipeline); @@ -4653,7 +4844,7 @@ RDD::PipelineID RenderingDeviceDriverVulkan::compute_pipeline_create(ShaderID p_ } VkPipeline vk_pipeline = VK_NULL_HANDLE; - VkResult err = vkCreateComputePipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, nullptr, &vk_pipeline); + VkResult err = vkCreateComputePipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE), &vk_pipeline); ERR_FAIL_COND_V_MSG(err, PipelineID(), "vkCreateComputePipelines failed with error " + itos(err) + "."); return PipelineID(vk_pipeline); @@ -4672,12 +4863,12 @@ RDD::QueryPoolID RenderingDeviceDriverVulkan::timestamp_query_pool_create(uint32 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); + vkCreateQueryPool(vk_device, &query_pool_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_QUERY_POOL), &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); + vkDestroyQueryPool(vk_device, (VkQueryPool)p_pool_id.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_QUERY_POOL)); } void RenderingDeviceDriverVulkan::timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) { @@ -4732,6 +4923,21 @@ void RenderingDeviceDriverVulkan::command_timestamp_write(CommandBufferID p_cmd_ void RenderingDeviceDriverVulkan::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) { const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + if (!functions.CmdBeginDebugUtilsLabelEXT) { + if (functions.CmdDebugMarkerBeginEXT) { + // Debug marker extensions. + VkDebugMarkerMarkerInfoEXT marker; + marker.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + marker.pNext = nullptr; + marker.pMarkerName = p_label_name; + marker.color[0] = p_color[0]; + marker.color[1] = p_color[1]; + marker.color[2] = p_color[2]; + marker.color[3] = p_color[3]; + functions.CmdDebugMarkerBeginEXT((VkCommandBuffer)p_cmd_buffer.id, &marker); + } + return; + } VkDebugUtilsLabelEXT label; label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; label.pNext = nullptr; @@ -4745,9 +4951,165 @@ void RenderingDeviceDriverVulkan::command_begin_label(CommandBufferID p_cmd_buff void RenderingDeviceDriverVulkan::command_end_label(CommandBufferID p_cmd_buffer) { const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + if (!functions.CmdEndDebugUtilsLabelEXT) { + if (functions.CmdDebugMarkerEndEXT) { + // Debug marker extensions. + functions.CmdDebugMarkerEndEXT((VkCommandBuffer)p_cmd_buffer.id); + } + return; + } functions.CmdEndDebugUtilsLabelEXT((VkCommandBuffer)p_cmd_buffer.id); } +/****************/ +/**** DEBUG *****/ +/****************/ +void RenderingDeviceDriverVulkan::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) { + if (p_data == BreadcrumbMarker::NONE) { + return; + } + vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, 0, sizeof(uint32_t), p_data); +} + +void RenderingDeviceDriverVulkan::on_device_lost() const { + if (device_functions.GetDeviceFaultInfoEXT == nullptr) { + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "VK_EXT_device_fault not available."); + return; + } + + VkDeviceFaultCountsEXT fault_counts = {}; + fault_counts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT; + VkResult vkres = device_functions.GetDeviceFaultInfoEXT(vk_device, &fault_counts, nullptr); + + if (vkres != VK_SUCCESS) { + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "vkGetDeviceFaultInfoEXT returned " + itos(vkres) + " when getting fault count, skipping VK_EXT_device_fault report..."); + return; + } + + String err_msg; + VkDeviceFaultInfoEXT fault_info = {}; + fault_info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT; + fault_info.pVendorInfos = fault_counts.vendorInfoCount + ? (VkDeviceFaultVendorInfoEXT *)memalloc(fault_counts.vendorInfoCount * sizeof(VkDeviceFaultVendorInfoEXT)) + : nullptr; + fault_info.pAddressInfos = + fault_counts.addressInfoCount + ? (VkDeviceFaultAddressInfoEXT *)memalloc(fault_counts.addressInfoCount * sizeof(VkDeviceFaultAddressInfoEXT)) + : nullptr; + fault_counts.vendorBinarySize = 0; + vkres = device_functions.GetDeviceFaultInfoEXT(vk_device, &fault_counts, &fault_info); + if (vkres != VK_SUCCESS) { + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "vkGetDeviceFaultInfoEXT returned " + itos(vkres) + " when getting fault info, skipping VK_EXT_device_fault report..."); + } else { + err_msg += "** Report from VK_EXT_device_fault **"; + err_msg += "\nDescription: " + String(fault_info.description); + err_msg += "\nVendor infos:"; + for (uint32_t vd = 0; vd < fault_counts.vendorInfoCount; ++vd) { + const VkDeviceFaultVendorInfoEXT *vendor_info = &fault_info.pVendorInfos[vd]; + err_msg += "\nInfo " + itos(vd); + err_msg += "\n Description: " + String(vendor_info->description); + err_msg += "\n Fault code : " + itos(vendor_info->vendorFaultCode); + err_msg += "\n Fault data : " + itos(vendor_info->vendorFaultData); + } + + static constexpr const char *addressTypeNames[] = { + "NONE", + "READ_INVALID", + "WRITE_INVALID", + "EXECUTE_INVALID", + "INSTRUCTION_POINTER_UNKNOWN", + "INSTRUCTION_POINTER_INVALID", + "INSTRUCTION_POINTER_FAULT", + }; + err_msg += "\nAddresses info:"; + for (uint32_t ad = 0; ad < fault_counts.addressInfoCount; ++ad) { + const VkDeviceFaultAddressInfoEXT *addr_info = &fault_info.pAddressInfos[ad]; + // From https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkDeviceFaultAddressInfoEXT.html + const VkDeviceAddress lower = (addr_info->reportedAddress & ~(addr_info->addressPrecision - 1)); + const VkDeviceAddress upper = (addr_info->reportedAddress | (addr_info->addressPrecision - 1)); + err_msg += "\nInfo " + itos(ad); + err_msg += "\n Type : " + String(addressTypeNames[addr_info->addressType]); + err_msg += "\n Reported address: " + itos(addr_info->reportedAddress); + err_msg += "\n Lower address : " + itos(lower); + err_msg += "\n Upper address : " + itos(upper); + err_msg += "\n Precision : " + itos(addr_info->addressPrecision); + } + } + + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, err_msg); + + if (fault_info.pVendorInfos) { + memfree(fault_info.pVendorInfos); + } + if (fault_info.pAddressInfos) { + memfree(fault_info.pAddressInfos); + } +} + +void RenderingDeviceDriverVulkan::print_lost_device_info() { +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) + void *breadcrumb_ptr; + vmaFlushAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, sizeof(uint32_t)); + vmaInvalidateAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, sizeof(uint32_t)); + + vmaMapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, &breadcrumb_ptr); + uint32_t last_breadcrumb = *(uint32_t *)breadcrumb_ptr; + vmaUnmapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle); + uint32_t phase = last_breadcrumb & uint32_t(~((1 << 16) - 1)); + uint32_t user_data = last_breadcrumb & ((1 << 16) - 1); + String error_msg = "Last known breadcrumb: "; + + switch (phase) { + case BreadcrumbMarker::ALPHA_PASS: + error_msg += "ALPHA_PASS"; + break; + case BreadcrumbMarker::BLIT_PASS: + error_msg += "BLIT_PASS"; + break; + case BreadcrumbMarker::DEBUG_PASS: + error_msg += "DEBUG_PASS"; + break; + case BreadcrumbMarker::LIGHTMAPPER_PASS: + error_msg += "LIGHTMAPPER_PASS"; + break; + case BreadcrumbMarker::OPAQUE_PASS: + error_msg += "OPAQUE_PASS"; + break; + case BreadcrumbMarker::POST_PROCESSING_PASS: + error_msg += "POST_PROCESSING_PASS"; + break; + case BreadcrumbMarker::REFLECTION_PROBES: + error_msg += "REFLECTION_PROBES"; + break; + case BreadcrumbMarker::SHADOW_PASS_CUBE: + error_msg += "SHADOW_PASS_CUBE"; + break; + case BreadcrumbMarker::SHADOW_PASS_DIRECTIONAL: + error_msg += "SHADOW_PASS_DIRECTIONAL"; + break; + case BreadcrumbMarker::SKY_PASS: + error_msg += "SKY_PASS"; + break; + case BreadcrumbMarker::TRANSPARENT_PASS: + error_msg += "TRANSPARENT_PASS"; + break; + case BreadcrumbMarker::UI_PASS: + error_msg += "UI_PASS"; + break; + default: + error_msg += "UNKNOWN_BREADCRUMB(" + itos((uint32_t)phase) + ')'; + break; + } + + if (user_data != 0) { + error_msg += " | User data: " + itos(user_data); + } + + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, error_msg); +#endif + on_device_lost(); +} + /********************/ /**** SUBMISSION ****/ /********************/ @@ -5010,9 +5372,12 @@ RenderingDeviceDriverVulkan::RenderingDeviceDriverVulkan(RenderingContextDriverV DEV_ASSERT(p_context_driver != nullptr); context_driver = p_context_driver; + max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool"); } RenderingDeviceDriverVulkan::~RenderingDeviceDriverVulkan() { + buffer_free(breadcrumb_buffer); + while (small_allocs_pools.size()) { HashMap::Iterator E = small_allocs_pools.begin(); vmaDestroyPool(allocator, E->value); @@ -5021,6 +5386,6 @@ RenderingDeviceDriverVulkan::~RenderingDeviceDriverVulkan() { vmaDestroyAllocator(allocator); if (vk_device != VK_NULL_HANDLE) { - vkDestroyDevice(vk_device, nullptr); + vkDestroyDevice(vk_device, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DEVICE)); } } diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 6847ae00bee4..2615d9824d34 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -111,7 +111,18 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { PFN_vkAcquireNextImageKHR AcquireNextImageKHR = nullptr; PFN_vkQueuePresentKHR QueuePresentKHR = nullptr; PFN_vkCreateRenderPass2KHR CreateRenderPass2KHR = nullptr; + + // Debug marker extensions. + PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT = nullptr; + PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT = nullptr; + PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT = nullptr; + PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT = nullptr; + + // Debug device fault. + PFN_vkGetDeviceFaultInfoEXT GetDeviceFaultInfoEXT = nullptr; }; + // Debug marker extensions. + VkDebugReportObjectTypeEXT _convert_to_debug_report_objectType(VkObjectType p_object_type); VkDevice vk_device = VK_NULL_HANDLE; RenderingContextDriverVulkan *context_driver = nullptr; @@ -132,6 +143,10 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { ShaderCapabilities shader_capabilities; StorageBufferCapabilities storage_buffer_capabilities; bool pipeline_cache_control_support = false; + bool device_fault_support = false; +#if defined(VK_TRACK_DEVICE_MEMORY) + bool device_memory_report_support = false; +#endif DeviceFunctions device_functions; void _register_requested_device_extension(const CharString &p_extension_name, bool p_required); @@ -160,10 +175,13 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { VmaPool _find_or_create_small_allocs_pool(uint32_t p_mem_type_index); +private: + BufferID breadcrumb_buffer; + +public: /*****************/ /**** BUFFERS ****/ /*****************/ -private: struct BufferInfo { VkBuffer vk_buffer = VK_NULL_HANDLE; struct { @@ -174,7 +192,6 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { 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; @@ -187,6 +204,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { /*****************/ struct TextureInfo { + VkImage vk_image = VK_NULL_HANDLE; VkImageView vk_view = VK_NULL_HANDLE; DataFormat rd_format = DATA_FORMAT_MAX; VkImageCreateInfo vk_create_info = {}; @@ -405,6 +423,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { 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; + virtual void shader_destroy_modules(ShaderID p_shader) override final; /*********************/ /**** UNIFORM SET ****/ /*********************/ @@ -606,6 +625,13 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final; virtual void command_end_label(CommandBufferID p_cmd_buffer) override final; + /****************/ + /**** DEBUG *****/ + /****************/ + virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final; + void print_lost_device_info(); + void on_device_lost() const; + /********************/ /**** SUBMISSION ****/ /********************/ @@ -620,6 +646,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { 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; @@ -651,4 +678,6 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { virtual ~RenderingDeviceDriverVulkan(); }; +using VKC = RenderingContextDriverVulkan; + #endif // RENDERING_DEVICE_DRIVER_VULKAN_H diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 24c770209010..733d85c46e74 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -14,3 +14,15 @@ Validate extension JSON: Error: Field 'classes/ShapeCast2D/properties/collision_ Validate extension JSON: Error: Field 'classes/ShapeCast3D/properties/collision_result': getter changed value in new API, from "_get_collision_result" to &"get_collision_result". These getters have been renamed to expose them. GDExtension language bindings couldn't have exposed these properties before. + + +GH-90993 +-------- +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments': size changed value in new API, from 9 to 10. +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments/9': type changed value in new API, from "Array" to "int". +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments/9': default_value changed value in new API, from "Array[RID]([])" to "0". +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list_begin/arguments/9': type changed value in new API, from "typedarray::RID" to "int". + +draw_list_begin added a new optional debug argument called breadcrumb. +There used to be an Array argument as arg #9 initially, then changed to typedarray::RID in 4.1, and finally removed in 4.3. +Since we're adding a new one at the same location, we need to silence those warnings for 4.1 and 4.3. diff --git a/misc/scripts/validate_extension_api.sh b/misc/scripts/validate_extension_api.sh index cde7a8574d66..88c5d8237427 100755 --- a/misc/scripts/validate_extension_api.sh +++ b/misc/scripts/validate_extension_api.sh @@ -8,6 +8,7 @@ fi if [ $# != 1 ]; then echo "Usage: @0 " + exit 1 fi api_validation_dir="$( dirname -- "$( dirname -- "${BASH_SOURCE[0]//\.\//}" )" )/extension_api_validation/" diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index d7c362a90821..50b552d733d4 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -715,7 +715,7 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int raster_push_constant.uv_offset[0] = -0.5f / float(atlas_size.x); raster_push_constant.uv_offset[1] = -0.5f / float(atlas_size.y); - RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors, 1.0, 0, Rect2(), RDD::BreadcrumbMarker::LIGHTMAPPER_PASS); //draw opaque rd->draw_list_bind_render_pipeline(draw_list, raster_pipeline); rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0); @@ -1919,7 +1919,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d seams_push_constant.slice = uint32_t(i * subslices + k); seams_push_constant.debug = debug; - RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i * subslices + k], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + // Store the current subslice in the breadcrumb. + RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i * subslices + k], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors, 1.0, 0, Rect2(), RDD::BreadcrumbMarker::LIGHTMAPPER_PASS | seams_push_constant.slice); rd->draw_list_bind_uniform_set(draw_list, raster_base_uniform, 0); rd->draw_list_bind_uniform_set(draw_list, blendseams_raster_uniform, 1); diff --git a/platform/android/rendering_context_driver_vulkan_android.cpp b/platform/android/rendering_context_driver_vulkan_android.cpp index 9232126b0475..a306a121f88c 100644 --- a/platform/android/rendering_context_driver_vulkan_android.cpp +++ b/platform/android/rendering_context_driver_vulkan_android.cpp @@ -50,7 +50,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_c create_info.window = wpd->window; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateAndroidSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateAndroidSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/platform/ios/rendering_context_driver_vulkan_ios.mm b/platform/ios/rendering_context_driver_vulkan_ios.mm index 6a6af1bc4191..8747bfd76abd 100644 --- a/platform/ios/rendering_context_driver_vulkan_ios.mm +++ b/platform/ios/rendering_context_driver_vulkan_ios.mm @@ -50,7 +50,7 @@ create_info.pLayer = *wpd->layer_ptr; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp index c874c45a8a65..0417ba95eb5c 100644 --- a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp +++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp @@ -51,7 +51,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_c create_info.surface = wpd->surface; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp index bf44062266d9..3f505d000c22 100644 --- a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp +++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp @@ -51,7 +51,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_creat create_info.window = wpd->window; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/platform/macos/rendering_context_driver_vulkan_macos.mm b/platform/macos/rendering_context_driver_vulkan_macos.mm index afefe5a6f7d4..b617cb8f266e 100644 --- a/platform/macos/rendering_context_driver_vulkan_macos.mm +++ b/platform/macos/rendering_context_driver_vulkan_macos.mm @@ -50,7 +50,7 @@ create_info.pLayer = *wpd->layer_ptr; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/platform/windows/rendering_context_driver_vulkan_windows.cpp b/platform/windows/rendering_context_driver_vulkan_windows.cpp index f968ffc1d785..445388af89fe 100644 --- a/platform/windows/rendering_context_driver_vulkan_windows.cpp +++ b/platform/windows/rendering_context_driver_vulkan_windows.cpp @@ -64,7 +64,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_c create_info.hwnd = wpd->window; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface); + VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); Surface *surface = memnew(Surface); diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index b5d31f541401..5dc67725f12b 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -1348,7 +1348,7 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD); + cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, Rect2(), RDD::BreadcrumbMarker::SKY_PASS | uint32_t(i)); _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 412fa643b1ef..48c226133d39 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -947,10 +947,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } { + RDD::BreadcrumbMarker breadcrumb; if (rb_data.is_valid()) { RD::get_singleton()->draw_command_begin_label("Render 3D Pass"); + breadcrumb = RDD::BreadcrumbMarker::OPAQUE_PASS; } else { RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass"); + breadcrumb = RDD::BreadcrumbMarker::REFLECTION_PROBES; } // opaque pass @@ -992,7 +995,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0, Rect2(), breadcrumb); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1089,7 +1092,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color render_list_params.framebuffer_format = fb_format; render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0. - draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE); + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector(), 0, 0, Rect2(), breadcrumb); _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); @@ -2181,9 +2184,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr } break; } - PipelineCacheRD *pipeline = nullptr; - - pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; + PipelineCacheRD *pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; RD::VertexFormatID vertex_format = -1; RID vertex_array_rd; @@ -2213,8 +2214,6 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants); if (pipeline_rd != prev_pipeline_rd) { - // checking with prev shader does not make so much sense, as - // the pipeline may still be different. RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd); prev_pipeline_rd = pipeline_rd; } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 5e4721dfb51d..6f90a9ca0d31 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1183,7 +1183,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors, 1, 0, Rect2(), RDD::BreadcrumbMarker::UI_PASS); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); @@ -1738,6 +1738,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() { state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures); } } + void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); diff --git a/servers/rendering/rendering_context_driver.cpp b/servers/rendering/rendering_context_driver.cpp index 19c0b0838c80..23e091e00c8c 100644 --- a/servers/rendering/rendering_context_driver.cpp +++ b/servers/rendering/rendering_context_driver.cpp @@ -83,3 +83,43 @@ void RenderingContextDriver::window_destroy(DisplayServer::WindowID p_window) { window_surface_map.erase(p_window); } + +const char *RenderingContextDriver::get_tracked_object_name(uint32_t p_type_index) const { + return "Tracking Unsupported by API"; +} + +uint64_t RenderingContextDriver::get_tracked_object_type_count() const { + return 0; +} + +uint64_t RenderingContextDriver::get_driver_total_memory() const { + return 0; +} + +uint64_t RenderingContextDriver::get_driver_allocation_count() const { + return 0; +} + +uint64_t RenderingContextDriver::get_driver_memory_by_object_type(uint32_t) const { + return 0; +} + +uint64_t RenderingContextDriver::get_driver_allocs_by_object_type(uint32_t) const { + return 0; +} + +uint64_t RenderingContextDriver::get_device_total_memory() const { + return 0; +} + +uint64_t RenderingContextDriver::get_device_allocation_count() const { + return 0; +} + +uint64_t RenderingContextDriver::get_device_memory_by_object_type(uint32_t) const { + return 0; +} + +uint64_t RenderingContextDriver::get_device_allocs_by_object_type(uint32_t) const { + return 0; +} diff --git a/servers/rendering/rendering_context_driver.h b/servers/rendering/rendering_context_driver.h index 539b3814a041..8449db442c3f 100644 --- a/servers/rendering/rendering_context_driver.h +++ b/servers/rendering/rendering_context_driver.h @@ -101,6 +101,19 @@ class RenderingContextDriver { virtual bool surface_get_needs_resize(SurfaceID p_surface) const = 0; virtual void surface_destroy(SurfaceID p_surface) = 0; virtual bool is_debug_utils_enabled() const = 0; + + virtual const char *get_tracked_object_name(uint32_t p_type_index) const; + virtual uint64_t get_tracked_object_type_count() const; + + virtual uint64_t get_driver_total_memory() const; + virtual uint64_t get_driver_allocation_count() const; + virtual uint64_t get_driver_memory_by_object_type(uint32_t p_type) const; + virtual uint64_t get_driver_allocs_by_object_type(uint32_t p_type) const; + + virtual uint64_t get_device_total_memory() const; + virtual uint64_t get_device_allocation_count() const; + virtual uint64_t get_device_memory_by_object_type(uint32_t p_type) const; + virtual uint64_t get_device_allocs_by_object_type(uint32_t p_type) const; }; #endif // RENDERING_CONTEXT_DRIVER_H diff --git a/servers/rendering/rendering_device.compat.inc b/servers/rendering/rendering_device.compat.inc index ee9481280aa7..77e44bbc5efb 100644 --- a/servers/rendering/rendering_device.compat.inc +++ b/servers/rendering/rendering_device.compat.inc @@ -86,7 +86,11 @@ RenderingDevice::FinalAction RenderingDevice::_convert_final_action_84976(FinalA } RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_84976(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) { - return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region); + return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, RDD::BreadcrumbMarker::NONE); +} + +RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_90993(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) { + 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, RDD::BreadcrumbMarker::NONE); } RenderingDevice::ComputeListID RenderingDevice::_compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap) { @@ -123,9 +127,11 @@ RenderingDevice::FramebufferFormatID RenderingDevice::_screen_get_framebuffer_fo void RenderingDevice::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::_shader_create_from_bytecode_bind_compat_79606); + ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_81356, DEFVAL(7)); ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_81356, DEFVAL(7)); ClassDB::bind_compatibility_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::_barrier_bind_compat_81356, DEFVAL(7), DEFVAL(7)); + ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_84976, DEFVAL(0x7FFF)); ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_84976, DEFVAL(0x7FFF)); ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_bind_compat_84976, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray())); @@ -136,7 +142,10 @@ void RenderingDevice::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::_texture_copy_bind_compat_84976, DEFVAL(0x7FFF)); ClassDB::bind_compatibility_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::_texture_clear_bind_compat_84976, DEFVAL(0x7FFF)); ClassDB::bind_compatibility_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::_texture_resolve_multisample_bind_compat_84976, DEFVAL(0x7FFF)); + ClassDB::bind_compatibility_method(D_METHOD("screen_get_framebuffer_format"), &RenderingDevice::_screen_get_framebuffer_format_bind_compat_87340); + + ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::_draw_list_begin_bind_compat_90993, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2())); } #endif diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index aef6978e2590..332e18bb6834 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -500,6 +500,8 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) { _THREAD_SAFE_METHOD_ + copy_bytes_count += p_size; + 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, @@ -513,9 +515,23 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p 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."); + gpu_copy_count++; + return _buffer_update(buffer, p_buffer, p_offset, (uint8_t *)p_data, p_size, true); } +String RenderingDevice::get_perf_report() const { + return perf_report_text; +} + +void RenderingDevice::update_perf_report() { + perf_report_text = " gpu:" + String::num_int64(gpu_copy_count); + perf_report_text += " bytes:" + String::num_int64(copy_bytes_count); + + gpu_copy_count = 0; + copy_bytes_count = 0; +} + Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) { _THREAD_SAFE_METHOD_ @@ -3575,7 +3591,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS clear_value.color = p_clear_color; RDD::RenderPassID render_pass = driver->swap_chain_get_render_pass(sc_it->value); - draw_graph.add_draw_list_begin(render_pass, fb_it->value, viewport, clear_value, true, false); + draw_graph.add_draw_list_begin(render_pass, fb_it->value, viewport, clear_value, true, false, RDD::BreadcrumbMarker::BLIT_PASS); _draw_list_set_viewport(viewport); _draw_list_set_scissor(viewport); @@ -3624,7 +3640,7 @@ Error RenderingDevice::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, 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) { +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, uint32_t p_breadcrumb) { thread_local LocalVector clear_values; thread_local LocalVector resource_trackers; thread_local LocalVector resource_usages; @@ -3672,7 +3688,7 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, } } - draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth); + draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth, p_breadcrumb); draw_graph.add_draw_list_usages(resource_trackers, resource_usages); // Mark textures as bound. @@ -3734,7 +3750,7 @@ void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Fram draw_graph.add_draw_list_clear_attachments(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) { +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, uint32_t p_breadcrumb) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); @@ -3780,7 +3796,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, 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); - 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); + 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, p_breadcrumb); if (err != OK) { return INVALID_ID; @@ -5195,6 +5211,8 @@ void RenderingDevice::_begin_frame() { frames[frame].draw_fence_signaled = false; } + update_perf_report(); + // Begin recording on the frame's command buffers. driver->begin_segment(frame, frames_drawn++); driver->command_buffer_begin(frames[frame].setup_command_buffer); @@ -5705,6 +5723,46 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r return driver->get_resource_native_handle(p_resource, driver_id); } +String RenderingDevice::get_tracked_object_name(uint32_t p_type_index) const { + return context->get_tracked_object_name(p_type_index); +} + +uint64_t RenderingDevice::get_tracked_object_type_count() const { + return context->get_tracked_object_type_count(); +} + +uint64_t RenderingDevice::get_driver_total_memory() const { + return context->get_driver_total_memory(); +} + +uint64_t RenderingDevice::get_driver_allocation_count() const { + return context->get_driver_allocation_count(); +} + +uint64_t RenderingDevice::get_driver_memory_by_object_type(uint32_t p_type) const { + return context->get_driver_memory_by_object_type(p_type); +} + +uint64_t RenderingDevice::get_driver_allocs_by_object_type(uint32_t p_type) const { + return context->get_driver_allocs_by_object_type(p_type); +} + +uint64_t RenderingDevice::get_device_total_memory() const { + return context->get_device_total_memory(); +} + +uint64_t RenderingDevice::get_device_allocation_count() const { + return context->get_device_allocation_count(); +} + +uint64_t RenderingDevice::get_device_memory_by_object_type(uint32_t type) const { + return context->get_device_memory_by_object_type(type); +} + +uint64_t RenderingDevice::get_device_allocs_by_object_type(uint32_t type) const { + return context->get_device_allocs_by_object_type(type); +} + uint32_t RenderingDevice::get_captured_timestamps_count() const { return frames[frame].timestamp_result_count; } @@ -5947,7 +6005,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color())); - ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::draw_list_begin, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2())); + ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "breadcrumb"), &RenderingDevice::draw_list_begin, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(0)); #ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray())); #endif @@ -6017,6 +6075,19 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource); + ClassDB::bind_method(D_METHOD("get_perf_report"), &RenderingDevice::get_perf_report); + + ClassDB::bind_method(D_METHOD("get_tracked_object_name", "type_index"), &RenderingDevice::get_tracked_object_name); + ClassDB::bind_method(D_METHOD("get_tracked_object_type_count"), &RenderingDevice::get_tracked_object_type_count); + ClassDB::bind_method(D_METHOD("get_driver_total_memory"), &RenderingDevice::get_driver_total_memory); + ClassDB::bind_method(D_METHOD("get_driver_allocation_count"), &RenderingDevice::get_driver_allocation_count); + ClassDB::bind_method(D_METHOD("get_driver_memory_by_object_type", "type"), &RenderingDevice::get_driver_memory_by_object_type); + ClassDB::bind_method(D_METHOD("get_driver_allocs_by_object_type", "type"), &RenderingDevice::get_driver_allocs_by_object_type); + ClassDB::bind_method(D_METHOD("get_device_total_memory"), &RenderingDevice::get_device_total_memory); + ClassDB::bind_method(D_METHOD("get_device_allocation_count"), &RenderingDevice::get_device_allocation_count); + ClassDB::bind_method(D_METHOD("get_device_memory_by_object_type", "type"), &RenderingDevice::get_device_memory_by_object_type); + ClassDB::bind_method(D_METHOD("get_device_allocs_by_object_type", "type"), &RenderingDevice::get_device_allocs_by_object_type); + BIND_ENUM_CONSTANT(DEVICE_TYPE_OTHER); BIND_ENUM_CONSTANT(DEVICE_TYPE_INTEGRATED_GPU); BIND_ENUM_CONSTANT(DEVICE_TYPE_DISCRETE_GPU); @@ -6539,6 +6610,20 @@ void RenderingDevice::_bind_methods() { BIND_CONSTANT(INVALID_ID); BIND_CONSTANT(INVALID_FORMAT_ID); + + BIND_ENUM_CONSTANT(NONE); + BIND_ENUM_CONSTANT(REFLECTION_PROBES); + BIND_ENUM_CONSTANT(SKY_PASS); + BIND_ENUM_CONSTANT(LIGHTMAPPER_PASS); + BIND_ENUM_CONSTANT(SHADOW_PASS_DIRECTIONAL); + BIND_ENUM_CONSTANT(SHADOW_PASS_CUBE); + BIND_ENUM_CONSTANT(OPAQUE_PASS); + BIND_ENUM_CONSTANT(ALPHA_PASS); + BIND_ENUM_CONSTANT(TRANSPARENT_PASS); + BIND_ENUM_CONSTANT(POST_PROCESSING_PASS); + BIND_ENUM_CONSTANT(BLIT_PASS); + BIND_ENUM_CONSTANT(UI_PASS); + BIND_ENUM_CONSTANT(DEBUG_PASS); } RenderingDevice::~RenderingDevice() { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 52f086e54f95..362fe499e4af 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -183,6 +183,12 @@ class RenderingDevice : public RenderingDeviceCommons { Buffer *_get_buffer_from_owner(RID p_buffer); Error _buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue = false, uint32_t p_required_align = 32); + void update_perf_report(); + + uint32_t gpu_copy_count = 0; + uint32_t copy_bytes_count = 0; + String perf_report_text; + RID_Owner uniform_buffer_owner; RID_Owner storage_buffer_owner; RID_Owner texture_buffer_owner; @@ -815,6 +821,7 @@ class RenderingDevice : public RenderingDeviceCommons { 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); + void _draw_list_end_bind_compat_84976(BitField p_post_barrier); void _compute_list_end_bind_compat_84976(BitField p_post_barrier); InitialAction _convert_initial_action_84976(InitialAction p_old_initial_action); @@ -827,7 +834,10 @@ class RenderingDevice : public RenderingDeviceCommons { Error _texture_copy_bind_compat_84976(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); Error _texture_clear_bind_compat_84976(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); Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField p_post_barrier); + FramebufferFormatID _screen_get_framebuffer_format_bind_compat_87340() const; + + DrawListID _draw_list_begin_bind_compat_90993(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()); #endif public: @@ -856,6 +866,7 @@ class RenderingDevice : public RenderingDeviceCommons { /******************/ /**** UNIFORMS ****/ /******************/ + String get_perf_report() const; enum StorageBufferUsage { STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1, @@ -1139,7 +1150,7 @@ class RenderingDevice : public RenderingDeviceCommons { 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); + 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, uint32_t p_breadcrumb); void _draw_list_set_viewport(Rect2i p_rect); void _draw_list_set_scissor(Rect2i p_rect); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); @@ -1148,7 +1159,7 @@ class RenderingDevice : public RenderingDeviceCommons { 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()); + 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(), uint32_t p_breadcrumb = 0); 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); @@ -1406,6 +1417,19 @@ class RenderingDevice : public RenderingDeviceCommons { uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0); + String get_tracked_object_name(uint32_t p_type_index) const; + uint64_t get_tracked_object_type_count() const; + + uint64_t get_driver_total_memory() const; + uint64_t get_driver_allocation_count() const; + uint64_t get_driver_memory_by_object_type(uint32_t p_type) const; + uint64_t get_driver_allocs_by_object_type(uint32_t p_type) const; + + uint64_t get_device_total_memory() const; + uint64_t get_device_allocation_count() const; + uint64_t get_device_memory_by_object_type(uint32_t p_type) const; + uint64_t get_device_allocs_by_object_type(uint32_t p_type) const; + static RenderingDevice *get_singleton(); RenderingDevice(); @@ -1478,6 +1502,7 @@ VARIANT_ENUM_CAST(RenderingDevice::FinalAction) VARIANT_ENUM_CAST(RenderingDevice::Limit) VARIANT_ENUM_CAST(RenderingDevice::MemoryType) VARIANT_ENUM_CAST(RenderingDevice::Features) +VARIANT_ENUM_CAST(RenderingDevice::BreadcrumbMarker) #ifndef DISABLE_DEPRECATED VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask); diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 918bf9b834ad..8c3996bd8043 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -271,6 +271,44 @@ class RenderingDeviceCommons : public Object { DATA_FORMAT_MAX, }; + // Breadcrumb markers are useful for debugging GPU crashes (i.e. DEVICE_LOST). Internally + // they're just an uint32_t to "tag" a GPU command. These are only used for debugging and do not + // (or at least shouldn't) alter the execution behavior in any way. + // + // When a GPU crashes and Godot was built in dev or debug mode; Godot will dump what commands + // were being executed and what tag they were marked with. + // This makes narrowing down the cause of a crash easier. Note that a GPU can be executing + // multiple commands at the same time. It is also useful to identify data hazards. + // + // For example if each LIGHTMAPPER_PASS must be executed in sequential order, but dumps + // indicated that pass (LIGHTMAPPER_PASS | 5) was being executed at the same time as + // (LIGHTMAPPER_PASS | 4), that would indicate there is a missing barrier or a render graph bug. + // + // The enums are bitshifted by 16 bits so it's possible to add user data via bitwise operations. + // Using this enum is not mandatory; but it is recommended so that all subsystems agree what each + // ID means when dumping info. + enum BreadcrumbMarker { + NONE = 0, + // Environment + REFLECTION_PROBES = 1u << 16u, + SKY_PASS = 2u << 16u, + // Light mapping + LIGHTMAPPER_PASS = 3u << 16u, + // Shadows + SHADOW_PASS_DIRECTIONAL = 4u << 16u, + SHADOW_PASS_CUBE = 5u << 16u, + // Geometry passes + OPAQUE_PASS = 6u << 16u, + ALPHA_PASS = 7u << 16u, + TRANSPARENT_PASS = 8u << 16u, + // Screen effects + POST_PROCESSING_PASS = 9u << 16u, + BLIT_PASS = 10u << 16u, + UI_PASS = 11u << 16u, + // Other + DEBUG_PASS = 12u << 16u, + }; + enum CompareOperator { COMPARE_OP_NEVER, COMPARE_OP_LESS, diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 934536ad9f4c..97c84c9d05f9 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -476,6 +476,7 @@ class RenderingDeviceDriver : public RenderingDeviceCommons { // 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; + virtual void shader_destroy_modules(ShaderID p_shader) = 0; protected: // An optional service to implementations. @@ -709,6 +710,11 @@ class RenderingDeviceDriver : public RenderingDeviceCommons { virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) = 0; virtual void command_end_label(CommandBufferID p_cmd_buffer) = 0; + /****************/ + /**** DEBUG *****/ + /****************/ + virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) = 0; + /********************/ /**** SUBMISSION ****/ /********************/ diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index 221ec72e4a43..abcb76cd43ad 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -823,6 +823,9 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC const RecordedDrawListCommand *draw_list_command = reinterpret_cast(command); const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count); +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) + driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb); +#endif driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values); _run_draw_list_command(r_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size); driver->command_end_render_pass(r_command_buffer); @@ -1399,8 +1402,9 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke _add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command); } -void RenderingDeviceGraph::add_compute_list_begin() { +void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) { compute_instruction_list.clear(); + compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1)); compute_instruction_list.index++; } @@ -1490,12 +1494,13 @@ void RenderingDeviceGraph::add_compute_list_end() { _add_command_to_graph(compute_instruction_list.command_trackers.ptr(), compute_instruction_list.command_tracker_usages.ptr(), compute_instruction_list.command_trackers.size(), command_index, command); } -void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView p_clear_values, bool p_uses_color, bool p_uses_depth) { +void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView p_clear_values, bool p_uses_color, bool p_uses_depth, uint32_t p_breadcrumb) { draw_instruction_list.clear(); draw_instruction_list.index++; draw_instruction_list.render_pass = p_render_pass; draw_instruction_list.framebuffer = p_framebuffer; draw_instruction_list.region = p_region; + draw_instruction_list.breadcrumb = p_breadcrumb; draw_instruction_list.clear_values.resize(p_clear_values.size()); for (uint32_t i = 0; i < p_clear_values.size(); i++) { draw_instruction_list.clear_values[i] = p_clear_values[i]; @@ -1706,6 +1711,7 @@ void RenderingDeviceGraph::add_draw_list_end() { command->framebuffer = draw_instruction_list.framebuffer; command->command_buffer_type = command_buffer_type; command->region = draw_instruction_list.region; + command->breadcrumb = draw_instruction_list.breadcrumb; command->clear_values_count = draw_instruction_list.clear_values.size(); RDD::RenderPassClearValue *clear_values = command->clear_values(); @@ -1964,6 +1970,7 @@ void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RD 2, // TYPE_TEXTURE_GET_DATA 2, // TYPE_TEXTURE_RESOLVE 2, // TYPE_TEXTURE_UPDATE + 2, // TYPE_INSERT_BREADCRUMB }; commands_sorted.clear(); diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h index baa15f63f611..e13e3a042987 100644 --- a/servers/rendering/rendering_device_graph.h +++ b/servers/rendering/rendering_device_graph.h @@ -218,13 +218,14 @@ class RenderingDeviceGraph { }; struct ComputeInstructionList : InstructionList { - // No extra contents. + uint32_t breadcrumb; }; struct DrawInstructionList : InstructionList { RDD::RenderPassID render_pass; RDD::FramebufferID framebuffer; Rect2i region; + uint32_t breadcrumb; LocalVector clear_values; }; @@ -296,6 +297,7 @@ class RenderingDeviceGraph { struct RecordedComputeListCommand : RecordedCommand { uint32_t instruction_data_size = 0; + uint32_t breadcrumb = 0; _FORCE_INLINE_ uint8_t *instruction_data() { return reinterpret_cast(&this[1]); @@ -312,6 +314,7 @@ class RenderingDeviceGraph { RDD::FramebufferID framebuffer; RDD::CommandBufferType command_buffer_type; Rect2i region; + uint32_t breadcrumb = 0; uint32_t clear_values_count = 0; _FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() { @@ -654,7 +657,7 @@ class RenderingDeviceGraph { void add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region); void add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region); void add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView p_buffer_copies); - void add_compute_list_begin(); + void add_compute_list_begin(RDD::BreadcrumbMarker p_phase = RDD::BreadcrumbMarker::NONE, uint32_t p_breadcrumb_data = 0); void add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline); void add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index); void add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups); @@ -664,7 +667,7 @@ class RenderingDeviceGraph { void add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage); void add_compute_list_usages(VectorView p_trackers, VectorView p_usages); void add_compute_list_end(); - void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView p_clear_values, bool p_uses_color, bool p_uses_depth); + void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView p_clear_values, bool p_uses_color, bool p_uses_depth, uint32_t p_breadcrumb = 0); void add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset); void add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField p_pipeline_stage_bits); void add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);