Merge pull request #90993 from darksylinc/matias-TheForge

Add debug utilities for Vulkan
This commit is contained in:
Rémi Verschelde 2024-08-22 00:38:22 +02:00 committed by GitHub
commit 568589c9d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 1321 additions and 108 deletions

View File

@ -35,6 +35,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *operator new(size_t p_size, const char *p_description) {
return Memory::alloc_static(p_size, false);
@ -65,6 +66,38 @@ SafeNumeric<uint64_t> Memory::max_usage;
SafeNumeric<uint64_t> 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;

View File

@ -62,6 +62,30 @@ public:
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();

View File

@ -218,6 +218,7 @@
<param index="6" name="clear_depth" type="float" default="1.0" />
<param index="7" name="clear_stencil" type="int" default="0" />
<param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<param index="9" name="breadcrumb" type="int" default="0" />
<description>
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]
</description>
</method>
<method name="draw_list_begin_for_screen">
@ -487,6 +493,31 @@
Returns the index of the last frame rendered that has rendering timestamps available for querying.
</description>
</method>
<method name="get_device_allocation_count" qualifiers="const">
<return type="int" />
<description>
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.
</description>
</method>
<method name="get_device_allocs_by_object_type" qualifiers="const">
<return type="int" />
<param index="0" name="type" type="int" />
<description>
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.
</description>
</method>
<method name="get_device_memory_by_object_type" qualifiers="const">
<return type="int" />
<param index="0" name="type" type="int" />
<description>
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.
</description>
</method>
<method name="get_device_name" qualifiers="const">
<return type="String" />
<description>
@ -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.
</description>
</method>
<method name="get_device_total_memory" qualifiers="const">
<return type="int" />
<description>
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.
</description>
</method>
<method name="get_device_vendor_name" qualifiers="const">
<return type="String" />
<description>
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].
</description>
</method>
<method name="get_driver_allocation_count" qualifiers="const">
<return type="int" />
<description>
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.
</description>
</method>
<method name="get_driver_allocs_by_object_type" qualifiers="const">
<return type="int" />
<param index="0" name="type" type="int" />
<description>
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.
</description>
</method>
<method name="get_driver_memory_by_object_type" qualifiers="const">
<return type="int" />
<param index="0" name="type" type="int" />
<description>
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.
</description>
</method>
<method name="get_driver_resource">
<return type="int" />
<param index="0" name="resource" type="int" enum="RenderingDevice.DriverResource" />
@ -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.
</description>
</method>
<method name="get_driver_total_memory" qualifiers="const">
<return type="int" />
<description>
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.
</description>
</method>
<method name="get_frame_delay" qualifiers="const">
<return type="int" />
<description>
@ -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].
</description>
</method>
<method name="get_perf_report" qualifiers="const">
<return type="String" />
<description>
Returns a string with a performance report from the past frame. Updates every frame.
</description>
</method>
<method name="get_tracked_object_name" qualifiers="const">
<return type="String" />
<param index="0" name="type_index" type="int" />
<description>
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.
</description>
</method>
<method name="get_tracked_object_type_count" qualifiers="const">
<return type="int" />
<description>
Returns how many types of trackable objects are.
This is only used by Vulkan in Debug builds.
</description>
</method>
<method name="index_array_create">
<return type="RID" />
<param index="0" name="index_buffer" type="RID" />
@ -2362,5 +2459,31 @@
<constant name="INVALID_FORMAT_ID" value="-1">
Returned by functions that return a format ID if a value is invalid.
</constant>
<constant name="NONE" value="0" enum="BreadcrumbMarker">
</constant>
<constant name="REFLECTION_PROBES" value="65536" enum="BreadcrumbMarker">
</constant>
<constant name="SKY_PASS" value="131072" enum="BreadcrumbMarker">
</constant>
<constant name="LIGHTMAPPER_PASS" value="196608" enum="BreadcrumbMarker">
</constant>
<constant name="SHADOW_PASS_DIRECTIONAL" value="262144" enum="BreadcrumbMarker">
</constant>
<constant name="SHADOW_PASS_CUBE" value="327680" enum="BreadcrumbMarker">
</constant>
<constant name="OPAQUE_PASS" value="393216" enum="BreadcrumbMarker">
</constant>
<constant name="ALPHA_PASS" value="458752" enum="BreadcrumbMarker">
</constant>
<constant name="TRANSPARENT_PASS" value="524288" enum="BreadcrumbMarker">
</constant>
<constant name="POST_PROCESSING_PASS" value="589824" enum="BreadcrumbMarker">
</constant>
<constant name="BLIT_PASS" value="655360" enum="BreadcrumbMarker">
</constant>
<constant name="UI_PASS" value="720896" enum="BreadcrumbMarker">
</constant>
<constant name="DEBUG_PASS" value="786432" enum="BreadcrumbMarker">
</constant>
</constants>
</class>

View File

@ -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 ****/
/********************/

View File

@ -714,6 +714,7 @@ public:
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
virtual uint32_t shader_get_layout_hash(ShaderID p_shader) override final;
virtual void shader_free(ShaderID p_shader) override final;
virtual void shader_destroy_modules(ShaderID p_shader) override final;
/*********************/
/**** UNIFORM SET ****/
@ -945,6 +946,11 @@ 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;
/****************/
/**** DEBUG *****/
/****************/
virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final;
/********************/
/**** SUBMISSION ****/
/********************/

View File

@ -231,6 +231,7 @@ public:
virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) override final;
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
virtual void shader_free(ShaderID p_shader) override final;
virtual void shader_destroy_modules(ShaderID p_shader) override final;
#pragma mark - Uniform Set
@ -376,6 +377,10 @@ 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;

View File

@ -2447,6 +2447,10 @@ void RenderingDeviceDriverMetal::shader_free(ShaderID p_shader) {
delete obj;
}
void RenderingDeviceDriverMetal::shader_destroy_modules(ShaderID p_shader) {
// TODO.
}
/*********************/
/**** UNIFORM SET ****/
/*********************/
@ -3541,6 +3545,12 @@ void RenderingDeviceDriverMetal::command_end_label(CommandBufferID p_cmd_buffer)
[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) {

View File

@ -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<size_t> driver_memory_total_memory;
SafeNumeric<size_t> driver_memory_total_alloc_count;
// Amount of driver memory for every object type.
SafeNumeric<size_t> driver_memory_tracker[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT][RenderingContextDriverVulkan::VK_TRACKED_SYSTEM_ALLOCATION_SCOPE_COUNT];
// Amount of allocations for every object type.
SafeNumeric<uint32_t> 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<uint64_t, size_t> memory_report_table;
// Total memory and allocation amount.
SafeNumeric<uint64_t> memory_report_total_memory;
SafeNumeric<uint64_t> memory_report_total_alloc_count;
// Amount of device memory for every object type.
SafeNumeric<size_t> memory_report_mem_usage[RenderingContextDriverVulkan::VK_TRACKED_OBJECT_TYPE_COUNT];
// Amount of device memory allocations for every object type.
SafeNumeric<size_t> 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<VkTrackedObjectType>(*reinterpret_cast<VkTrackedObjectType *>(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<uint8_t *>(Memory::alloc_aligned_static(size + alignment, alignment));
if (ret == nullptr) {
return nullptr;
}
// Track allocation
TrackedMemHeader *header = reinterpret_cast<TrackedMemHeader *>(ret);
header->size = size;
header->allocation_scope = allocation_scope;
header->type = type;
*reinterpret_cast<size_t *>(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<VkObjectType>(*reinterpret_cast<uint32_t *>(p_user_data));
return get_allocation_callbacks(type)->pfnAllocation(p_user_data, size, alignment, allocation_scope);
}
uint8_t *mem = reinterpret_cast<uint8_t *>(p_original);
// Retrieve alignment
alignment = *reinterpret_cast<size_t *>(mem - sizeof(size_t));
// Retrieve allocation data
TrackedMemHeader *header = reinterpret_cast<TrackedMemHeader *>(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<uint8_t *>(Memory::realloc_aligned_static(header, size + alignment, header->size + alignment, alignment));
if (ret == nullptr) {
return nullptr;
}
// Update tracker
header = reinterpret_cast<TrackedMemHeader *>(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<uint8_t *>(p_memory);
size_t alignment = *reinterpret_cast<size_t *>(mem - sizeof(size_t));
TrackedMemHeader *header = reinterpret_cast<TrackedMemHeader *>(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);
}

View File

@ -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 <volk.h>
#else
@ -77,6 +82,12 @@ public:
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 @@ private:
// 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<const char *> &r_layer_names) const;
@ -153,6 +166,43 @@ public:
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;
};

View File

@ -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 LocalVector<VkDevice
create_info_next = &pipeline_cache_control_features;
}
VkPhysicalDeviceFaultFeaturesEXT device_fault_features = {};
if (device_fault_support) {
device_fault_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
device_fault_features.pNext = create_info_next;
create_info_next = &device_fault_features;
}
#if defined(VK_TRACK_DEVICE_MEMORY)
VkDeviceDeviceMemoryReportCreateInfoEXT memory_report_info = {};
if (device_memory_report_support) {
memory_report_info.sType = VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT;
memory_report_info.pfnUserCallback = RenderingContextDriverVulkan::memory_report_callback;
memory_report_info.pNext = create_info_next;
memory_report_info.flags = 0;
memory_report_info.pUserData = this;
create_info_next = &memory_report_info;
}
#endif
VkPhysicalDeviceVulkan11Features vulkan_1_1_features = {};
VkPhysicalDevice16BitStorageFeaturesKHR storage_features = {};
VkPhysicalDeviceMultiviewFeatures multiview_features = {};
@ -968,7 +1015,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVector<VkDevice
bool device_created = VulkanHooks::get_singleton()->create_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 LocalVector<VkDevice
if (enabled_device_extension_names.has(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
device_functions.CreateRenderPass2KHR = PFN_vkCreateRenderPass2KHR(functions.GetDeviceProcAddr(vk_device, "vkCreateRenderPass2KHR"));
}
// Debug marker extensions.
if (enabled_device_extension_names.has(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
device_functions.CmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)functions.GetDeviceProcAddr(vk_device, "vkCmdDebugMarkerBeginEXT");
device_functions.CmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)functions.GetDeviceProcAddr(vk_device, "vkCmdDebugMarkerEndEXT");
device_functions.CmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)functions.GetDeviceProcAddr(vk_device, "vkCmdDebugMarkerInsertEXT");
device_functions.DebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)functions.GetDeviceProcAddr(vk_device, "vkDebugMarkerSetObjectNameEXT");
}
// Debug device fault extension.
if (device_fault_support) {
device_functions.GetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT)functions.GetDeviceProcAddr(vk_device, "vkGetDeviceFaultInfoEXT");
}
}
return OK;
@ -1148,17 +1208,102 @@ bool RenderingDeviceDriverVulkan::_recreate_image_semaphore(CommandQueue *p_comm
VkSemaphore semaphore;
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, false);
// Indicate the semaphore is free again and destroy the previous one before storing the new one.
vkDestroySemaphore(vk_device, p_command_queue->image_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<BufferInfo>(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<TextureInfo>(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<RDD::TextureUsageBits> 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<VkDescriptorPool, uint32_t>::Iterator pool_rcs_it = p_pool_sets_it->value.find(p_vk_descriptor_pool);
pool_rcs_it->value--;
if (pool_rcs_it->value == 0) {
vkDestroyDescriptorPool(vk_device, p_vk_descriptor_pool, nullptr);
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<uint8_t> &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<uint8_t> &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(VectorView<Att
}
VkRenderPass vk_render_pass = VK_NULL_HANDLE;
VkResult res = _create_render_pass(vk_device, &create_info, nullptr, &vk_render_pass);
VkResult res = _create_render_pass(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_RENDER_PASS), &vk_render_pass);
ERR_FAIL_COND_V_MSG(res, RenderPassID(), "vkCreateRenderPass2KHR failed with error " + itos(res) + ".");
return RenderPassID(vk_render_pass);
}
void RenderingDeviceDriverVulkan::render_pass_free(RenderPassID p_render_pass) {
vkDestroyRenderPass(vk_device, (VkRenderPass)p_render_pass.id, nullptr);
vkDestroyRenderPass(vk_device, (VkRenderPass)p_render_pass.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_RENDER_PASS));
}
// ----- COMMANDS -----
@ -4550,6 +4739,8 @@ RDD::PipelineID RenderingDeviceDriverVulkan::render_pipeline_create(
pipeline_create_info.pNext = graphics_pipeline_nextptr;
pipeline_create_info.stageCount = shader_info->vk_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<uint32_t, VmaPool>::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));
}
}

View File

@ -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 @@ private:
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 @@ private:
VkBufferView vk_view = VK_NULL_HANDLE; // For texel buffers.
};
public:
virtual BufferID buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type) override final;
virtual bool buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) override final;
virtual void buffer_free(BufferID p_buffer) override final;
@ -187,6 +204,7 @@ public:
/*****************/
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 @@ public:
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
virtual void shader_free(ShaderID p_shader) override final;
virtual void shader_destroy_modules(ShaderID p_shader) override final;
/*********************/
/**** UNIFORM SET ****/
/*********************/
@ -606,6 +625,13 @@ 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;
/****************/
/**** 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 @@ public:
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 @@ public:
virtual ~RenderingDeviceDriverVulkan();
};
using VKC = RenderingContextDriverVulkan;
#endif // RENDERING_DEVICE_DRIVER_VULKAN_H

View File

@ -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.

View File

@ -8,6 +8,7 @@ fi
if [ $# != 1 ]; then
echo "Usage: @0 <path-to-godot-executable>"
exit 1
fi
api_validation_dir="$( dirname -- "$( dirname -- "${BASH_SOURCE[0]//\.\//}" )" )/extension_api_validation/"

View File

@ -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);

View File

@ -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);

View File

@ -50,7 +50,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanIOS::surface_creat
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);

View File

@ -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);

View File

@ -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);

View File

@ -50,7 +50,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanMacOS::surface_cre
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);

View File

@ -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);

View File

@ -1348,7 +1348,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> 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<Color>(), 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();
}

View File

@ -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<Color>(), 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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -101,6 +101,19 @@ public:
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

View File

@ -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<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &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<Color> &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<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
@ -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<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()));
}
#endif

View File

@ -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<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass) {
Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, uint32_t p_breadcrumb) {
thread_local LocalVector<RDD::RenderPassClearValue> clear_values;
thread_local LocalVector<RDG::ResourceTracker *> resource_trackers;
thread_local LocalVector<RDG::ResourceUsage> 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<Color> &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<Color> &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<Color>()), 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<Color>()), 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<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
#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() {

View File

@ -183,6 +183,12 @@ private:
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<Buffer> uniform_buffer_owner;
RID_Owner<Buffer> storage_buffer_owner;
RID_Owner<Buffer> texture_buffer_owner;
@ -815,6 +821,7 @@ private:
void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to);
void _draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
void _compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
InitialAction _convert_initial_action_84976(InitialAction p_old_initial_action);
@ -827,7 +834,10 @@ private:
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<BarrierMask> 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<BarrierMask> p_post_barrier);
Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> 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<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
#endif
public:
@ -856,6 +866,7 @@ public:
/******************/
/**** UNIFORMS ****/
/******************/
String get_perf_report() const;
enum StorageBufferUsage {
STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1,
@ -1139,7 +1150,7 @@ private:
void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count);
Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass);
Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, 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 @@ private:
public:
DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), 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 @@ public:
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);

View File

@ -271,6 +271,44 @@ public:
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,

View File

@ -476,6 +476,7 @@ public:
// 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 @@ public:
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 ****/
/********************/

View File

@ -823,6 +823,9 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(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<RDD::RenderPassClearValue> 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<RDD::RenderPassClearValue> 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();

View File

@ -218,13 +218,14 @@ private:
};
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<RDD::RenderPassClearValue> clear_values;
};
@ -296,6 +297,7 @@ private:
struct RecordedComputeListCommand : RecordedCommand {
uint32_t instruction_data_size = 0;
uint32_t breadcrumb = 0;
_FORCE_INLINE_ uint8_t *instruction_data() {
return reinterpret_cast<uint8_t *>(&this[1]);
@ -312,6 +314,7 @@ private:
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 @@ public:
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<RecordedBufferCopy> 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 @@ public:
void add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage);
void add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> 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<RDD::RenderPassClearValue> 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<RDD::RenderPassClearValue> 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<RDD::PipelineStageBits> p_pipeline_stage_bits);
void add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);