summaryrefslogtreecommitdiffstats
path: root/drivers/vulkan/rendering_device_driver_vulkan.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/vulkan/rendering_device_driver_vulkan.cpp')
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp894
1 files changed, 801 insertions, 93 deletions
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
index 97fd156584..a86f72e0b9 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp
@@ -35,6 +35,16 @@
#include "thirdparty/misc/smolv.h"
#include "vulkan_hooks.h"
+#if defined(ANDROID_ENABLED)
+#include "platform/android/java_godot_wrapper.h"
+#include "platform/android/os_android.h"
+#include "platform/android/thread_jandroid.h"
+#endif
+
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+#include "thirdparty/swappy-frame-pacing/swappyVk.h"
+#endif
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define PRINT_NATIVE_COMMANDS 0
@@ -43,6 +53,10 @@
/**** GENERIC ****/
/*****************/
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+static const uint32_t BREADCRUMB_BUFFER_ENTRIES = 512u;
+#endif
+
static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = {
VK_FORMAT_R4G4_UNORM_PACK8,
VK_FORMAT_R4G4B4A4_UNORM_PACK16,
@@ -266,6 +280,7 @@ static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = {
static VkImageLayout RD_TO_VK_LAYOUT[RDD::TEXTURE_LAYOUT_MAX] = {
VK_IMAGE_LAYOUT_UNDEFINED, // TEXTURE_LAYOUT_UNDEFINED
+ VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_GENERAL
VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_STORAGE_OPTIMAL
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
@@ -497,11 +512,32 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() {
_register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false);
_register_requested_device_extension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, false);
_register_requested_device_extension(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
+ _register_requested_device_extension(VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, false);
if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
_register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true);
}
+#if defined(VK_TRACK_DEVICE_MEMORY)
+ if (Engine::get_singleton()->is_extra_gpu_memory_tracking_enabled()) {
+ _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);
@@ -512,6 +548,37 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() {
err = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &device_extension_count, device_extensions.ptr());
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ if (swappy_frame_pacer_enable) {
+ char **swappy_required_extensions;
+ uint32_t swappy_required_extensions_count = 0;
+ // Determine number of extensions required by Swappy frame pacer.
+ SwappyVk_determineDeviceExtensions(physical_device, device_extension_count, device_extensions.ptr(), &swappy_required_extensions_count, nullptr);
+
+ if (swappy_required_extensions_count < device_extension_count) {
+ // Determine the actual extensions.
+ swappy_required_extensions = (char **)malloc(swappy_required_extensions_count * sizeof(char *));
+ char *pRequiredExtensionsData = (char *)malloc(swappy_required_extensions_count * (VK_MAX_EXTENSION_NAME_SIZE + 1));
+ for (uint32_t i = 0; i < swappy_required_extensions_count; i++) {
+ swappy_required_extensions[i] = &pRequiredExtensionsData[i * (VK_MAX_EXTENSION_NAME_SIZE + 1)];
+ }
+ SwappyVk_determineDeviceExtensions(physical_device, device_extension_count,
+ device_extensions.ptr(), &swappy_required_extensions_count, swappy_required_extensions);
+
+ // Enable extensions requested by Swappy.
+ for (uint32_t i = 0; i < swappy_required_extensions_count; i++) {
+ CharString extension_name(swappy_required_extensions[i]);
+ if (requested_device_extensions.has(extension_name)) {
+ enabled_device_extension_names.insert(extension_name);
+ }
+ }
+
+ free(pRequiredExtensionsData);
+ free(swappy_required_extensions);
+ }
+ }
+#endif
+
#ifdef DEV_ENABLED
for (uint32_t i = 0; i < device_extension_count; i++) {
print_verbose(String("VULKAN: Found device extension ") + String::utf8(device_extensions[i].extensionName));
@@ -745,6 +812,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 +989,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 +1064,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 +1085,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 +1257,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 +1365,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);
}
}
@@ -1212,6 +1416,22 @@ Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t
max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool");
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ breadcrumb_buffer = buffer_create(2u * sizeof(uint32_t) * BREADCRUMB_BUFFER_ENTRIES, BufferUsageBits::BUFFER_USAGE_TRANSFER_TO_BIT, MemoryAllocationType::MEMORY_ALLOCATION_TYPE_CPU);
+#endif
+
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ swappy_frame_pacer_enable = GLOBAL_GET("display/window/frame_pacing/android/enable_frame_pacing");
+ swappy_mode = GLOBAL_GET("display/window/frame_pacing/android/swappy_mode");
+
+ if (VulkanHooks::get_singleton() != nullptr) {
+ // Hooks control device creation & possibly presentation
+ // (e.g. OpenXR) thus it's too risky to use Swappy.
+ swappy_frame_pacer_enable = false;
+ OS::get_singleton()->print("VulkanHooks detected (e.g. OpenXR): Force-disabling Swappy Frame Pacing.\n");
+ }
+#endif
+
return OK;
}
@@ -1279,11 +1499,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 +1514,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, nullptr);
+ 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 +1543,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 +1552,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 +1728,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 +1740,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, nullptr);
+ ERR_FAIL_COND_V_MSG(err, TextureID(), "Can't bind memory to image, error: " + itos(err) + ".");
// Create view.
@@ -1536,16 +1767,28 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat &
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
+ VkImageViewASTCDecodeModeEXT decode_mode;
+ if (enabled_device_extension_names.has(VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME)) {
+ if (image_view_create_info.format >= VK_FORMAT_ASTC_4x4_UNORM_BLOCK && image_view_create_info.format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK) {
+ decode_mode.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT;
+ decode_mode.pNext = nullptr;
+ decode_mode.decodeMode = VK_FORMAT_R8G8B8A8_UNORM;
+ image_view_create_info.pNext = &decode_mode;
+ }
+ }
+
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 +1822,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) + ".");
}
@@ -1590,16 +1833,17 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_from_extension(uint64
tex_info->vk_view = vk_image_view;
tex_info->rd_format = p_format;
tex_info->vk_view_create_info = image_view_create_info;
-
+#ifdef DEBUG_ENABLED
+ tex_info->created_from_extension = true;
+#endif
return TextureID(tex_info);
}
RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+ ERR_FAIL_COND_V(!owner_tex_info->allocation.handle && !owner_tex_info->created_from_extension, TextureID());
#endif
-
VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
@@ -1634,7 +1878,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.
@@ -1655,7 +1899,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_or
RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+ ERR_FAIL_COND_V(!owner_tex_info->allocation.handle && !owner_tex_info->created_from_extension, TextureID());
#endif
VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
@@ -1687,7 +1931,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 +1951,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 +2033,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 +2114,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 +2296,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 +2307,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 +2338,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 +2350,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));
}
/******************/
@@ -2169,6 +2417,14 @@ RDD::CommandQueueID RenderingDeviceDriverVulkan::command_queue_create(CommandQue
ERR_FAIL_COND_V_MSG(picked_queue_index >= queue_family.size(), CommandQueueID(), "A queue in the picked family could not be found.");
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ if (swappy_frame_pacer_enable) {
+ VkQueue selected_queue;
+ vkGetDeviceQueue(vk_device, family_index, picked_queue_index, &selected_queue);
+ SwappyVk_setQueueFamilyIndex(vk_device, selected_queue, family_index);
+ }
+#endif
+
// Create the virtual queue.
CommandQueue *command_queue = memnew(CommandQueue);
command_queue->queue_family = family_index;
@@ -2236,7 +2492,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 +2519,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()) {
@@ -2309,7 +2570,16 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu
present_info.pResults = results.ptr();
device_queue.submit_mutex.lock();
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ if (swappy_frame_pacer_enable) {
+ err = SwappyVk_queuePresent(device_queue.queue, &present_info);
+ } else {
+ err = device_functions.QueuePresentKHR(device_queue.queue, &present_info);
+ }
+#else
err = device_functions.QueuePresentKHR(device_queue.queue, &present_info);
+#endif
+
device_queue.submit_mutex.unlock();
// Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired.
@@ -2341,7 +2611,10 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu
// it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain
// every frame.
- ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED);
+ ERR_FAIL_COND_V_MSG(
+ err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR,
+ FAILED,
+ "QueuePresentKHR failed with error: " + get_vulkan_result(err));
}
return OK;
@@ -2354,12 +2627,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 +2660,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 +2673,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);
}
@@ -2444,11 +2717,13 @@ bool RenderingDeviceDriverVulkan::command_buffer_begin(CommandBufferID p_cmd_buf
bool RenderingDeviceDriverVulkan::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {
// Reset is implicit (VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT).
+ Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
+
VkCommandBufferInheritanceInfo inheritance_info = {};
inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritance_info.renderPass = (VkRenderPass)p_render_pass.id;
inheritance_info.subpass = p_subpass;
- inheritance_info.framebuffer = (VkFramebuffer)p_framebuffer.id;
+ inheritance_info.framebuffer = framebuffer->vk_framebuffer;
VkCommandBufferBeginInfo cmd_buf_begin_info = {};
cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -2480,7 +2755,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 +2764,15 @@ 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);
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ if (swappy_frame_pacer_enable) {
+ // Swappy has a bug where the ANativeWindow will be leaked if we call
+ // SwappyVk_destroySwapchain, so we must release it by hand.
+ SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, nullptr);
+ SwappyVk_destroySwapchain(vk_device, swap_chain->vk_swapchain);
+ }
+#endif
+ 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 +2854,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);
@@ -2605,9 +2888,30 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
VkResult err = functions.GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface->vk_surface, &surface_capabilities);
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+ // No swapchain yet, this is the first time we're creating it.
+ if (!swap_chain->vk_swapchain) {
+ if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) {
+ // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities.
+ // We make sure to overwrite surface_capabilities.currentExtent.width so that the same check further below
+ // does not set extent.width = CLAMP( surface->width, ... ) on the first run of this function, because
+ // that'd be potentially unswapped.
+ surface_capabilities.currentExtent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
+ surface_capabilities.currentExtent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height);
+ }
+
+ // We must SWAP() only once otherwise we'll keep ping-ponging between
+ // the right and wrong resolutions after multiple calls to swap_chain_resize().
+ if (surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
+ surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
+ // Swap to get identity width and height.
+ SWAP(surface_capabilities.currentExtent.width, surface_capabilities.currentExtent.height);
+ }
+ }
+
VkExtent2D extent;
if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) {
// The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities.
+ // We can only be here on the second call to swap_chain_resize(), by which time surface->width & surface->height should already be swapped if needed.
extent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
extent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height);
} else {
@@ -2655,9 +2959,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
}
bool present_mode_available = present_modes.has(present_mode);
- if (present_mode_available) {
- print_verbose("Using present mode: " + present_mode_name);
- } else {
+ if (!present_mode_available) {
// Present mode is not available, fall back to FIFO which is guaranteed to be supported.
WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_name));
surface->vsync_mode = DisplayServer::VSYNC_ENABLED;
@@ -2671,15 +2973,8 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
desired_swapchain_images = MIN(desired_swapchain_images, surface_capabilities.maxImageCount);
}
- // Prefer identity transform if it's supported, use the current transform otherwise.
- // This behavior is intended as Godot does not supported native rotation in platforms that use these bits.
// Refer to the comment in command_queue_present() for more details.
- VkSurfaceTransformFlagBitsKHR surface_transform_bits;
- if (surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
- surface_transform_bits = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- } else {
- surface_transform_bits = surface_capabilities.currentTransform;
- }
+ VkSurfaceTransformFlagBitsKHR surface_transform_bits = surface_capabilities.currentTransform;
VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
if (OS::get_singleton()->is_layered_allowed() || !(surface_capabilities.supportedCompositeAlpha & composite_alpha)) {
@@ -2711,12 +3006,60 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
swap_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swap_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swap_create_info.preTransform = surface_transform_bits;
+ switch (swap_create_info.preTransform) {
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ swap_chain->pre_transform_rotation_degrees = 0;
+ break;
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ swap_chain->pre_transform_rotation_degrees = 90;
+ break;
+ case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+ swap_chain->pre_transform_rotation_degrees = 180;
+ break;
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ swap_chain->pre_transform_rotation_degrees = 270;
+ break;
+ default:
+ WARN_PRINT("Unexpected swap_create_info.preTransform = " + itos(swap_create_info.preTransform) + ".");
+ swap_chain->pre_transform_rotation_degrees = 0;
+ break;
+ }
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);
+#if defined(SWAPPY_FRAME_PACING_ENABLED)
+ if (swappy_frame_pacer_enable) {
+ SwappyVk_initAndGetRefreshCycleDuration(get_jni_env(), static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity(), physical_device,
+ vk_device, swap_chain->vk_swapchain, &swap_chain->refresh_duration);
+ SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, static_cast<OS_Android *>(OS::get_singleton())->get_native_window());
+ SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, swap_chain->refresh_duration);
+
+ enum SwappyModes {
+ PIPELINE_FORCED_ON,
+ AUTO_FPS_PIPELINE_FORCED_ON,
+ AUTO_FPS_AUTO_PIPELINE,
+ };
+
+ switch (swappy_mode) {
+ case PIPELINE_FORCED_ON:
+ SwappyVk_setAutoSwapInterval(true);
+ SwappyVk_setAutoPipelineMode(true);
+ break;
+ case AUTO_FPS_PIPELINE_FORCED_ON:
+ SwappyVk_setAutoSwapInterval(true);
+ SwappyVk_setAutoPipelineMode(false);
+ break;
+ case AUTO_FPS_AUTO_PIPELINE:
+ SwappyVk_setAutoSwapInterval(false);
+ SwappyVk_setAutoPipelineMode(false);
+ break;
+ }
+ }
+#endif
+
uint32_t image_count = 0;
err = device_functions.GetSwapchainImagesKHR(vk_device, swap_chain->vk_swapchain, &image_count, nullptr);
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
@@ -2742,7 +3085,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);
@@ -2758,12 +3101,16 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
fb_create_info.height = surface->height;
fb_create_info.layers = 1;
- VkFramebuffer framebuffer;
+ VkFramebuffer vk_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), &vk_framebuffer);
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+ Framebuffer *framebuffer = memnew(Framebuffer);
+ framebuffer->vk_framebuffer = vk_framebuffer;
+ framebuffer->swap_chain_image = swap_chain->images[i];
+ framebuffer->swap_chain_image_subresource_range = view_create_info.subresourceRange;
swap_chain->framebuffers.push_back(RDD::FramebufferID(framebuffer));
}
@@ -2792,7 +3139,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();
@@ -2832,7 +3179,10 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(C
command_queue->pending_semaphores_for_fence.push_back(semaphore_index);
// Return the corresponding framebuffer to the new current image.
- return swap_chain->framebuffers[swap_chain->image_index];
+ FramebufferID framebuffer_id = swap_chain->framebuffers[swap_chain->image_index];
+ Framebuffer *framebuffer = (Framebuffer *)(framebuffer_id.id);
+ framebuffer->swap_chain_acquired = true;
+ return framebuffer_id;
}
RDD::RenderPassID RenderingDeviceDriverVulkan::swap_chain_get_render_pass(SwapChainID p_swap_chain) {
@@ -2842,6 +3192,13 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::swap_chain_get_render_pass(SwapCh
return swap_chain->render_pass;
}
+int RenderingDeviceDriverVulkan::swap_chain_get_pre_rotation_degrees(SwapChainID p_swap_chain) {
+ DEV_ASSERT(p_swap_chain.id != 0);
+
+ SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
+ return swap_chain->pre_transform_rotation_degrees;
+}
+
RDD::DataFormat RenderingDeviceDriverVulkan::swap_chain_get_format(SwapChainID p_swap_chain) {
DEV_ASSERT(p_swap_chain.id != 0);
@@ -2857,6 +3214,22 @@ RDD::DataFormat RenderingDeviceDriverVulkan::swap_chain_get_format(SwapChainID p
}
}
+void RenderingDeviceDriverVulkan::swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) {
+ DEV_ASSERT(p_swap_chain.id != 0);
+
+#ifdef SWAPPY_FRAME_PACING_ENABLED
+ if (!swappy_frame_pacer_enable) {
+ return;
+ }
+
+ SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
+ if (swap_chain->vk_swapchain != VK_NULL_HANDLE) {
+ const uint64_t max_time = p_max_fps > 0 ? uint64_t((1000.0 * 1000.0 * 1000.0) / p_max_fps) : 0;
+ SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, MAX(swap_chain->refresh_duration, max_time));
+ }
+#endif
+}
+
void RenderingDeviceDriverVulkan::swap_chain_free(SwapChainID p_swap_chain) {
DEV_ASSERT(p_swap_chain.id != 0);
@@ -2864,7 +3237,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 +3263,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
@@ -2901,11 +3274,15 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID
}
#endif
- return FramebufferID(vk_framebuffer);
+ Framebuffer *framebuffer = memnew(Framebuffer);
+ framebuffer->vk_framebuffer = vk_framebuffer;
+ return FramebufferID(framebuffer);
}
void RenderingDeviceDriverVulkan::framebuffer_free(FramebufferID p_framebuffer) {
- vkDestroyFramebuffer(vk_device, (VkFramebuffer)p_framebuffer.id, nullptr);
+ Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
+ vkDestroyFramebuffer(vk_device, framebuffer->vk_framebuffer, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER));
+ memdelete(framebuffer);
}
/****************/
@@ -3282,7 +3659,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 +3686,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 +3713,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 +3722,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 +3742,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 +3862,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 +3882,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);
@@ -3661,7 +4049,7 @@ RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorView<Bou
}
// Need a descriptor pool.
- DescriptorSetPools::Iterator pool_sets_it = {};
+ DescriptorSetPools::Iterator pool_sets_it;
VkDescriptorPool vk_pool = _descriptor_set_pool_find_or_create(pool_key, &pool_sets_it);
DEV_ASSERT(vk_pool);
pool_sets_it->value[vk_pool]++;
@@ -3839,7 +4227,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 -----
@@ -3900,11 +4288,7 @@ bool RenderingDeviceDriverVulkan::pipeline_cache_create(const Vector<uint8_t> &p
cache_info.initialDataSize = pipelines_cache.buffer.size() - sizeof(PipelineCacheHeader);
cache_info.pInitialData = pipelines_cache.buffer.ptr() + sizeof(PipelineCacheHeader);
- if (pipeline_cache_control_support) {
- 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 +4301,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 +4485,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 -----
@@ -4116,10 +4500,25 @@ void RenderingDeviceDriverVulkan::render_pass_free(RenderPassID p_render_pass) {
static_assert(ARRAYS_COMPATIBLE_FIELDWISE(RDD::RenderPassClearValue, VkClearValue));
void RenderingDeviceDriverVulkan::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) {
+ Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
+ if (framebuffer->swap_chain_acquired) {
+ // Insert a barrier to wait for the acquisition of the framebuffer before the render pass begins.
+ VkImageMemoryBarrier image_barrier = {};
+ image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ image_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_barrier.image = framebuffer->swap_chain_image;
+ image_barrier.subresourceRange = framebuffer->swap_chain_image_subresource_range;
+ vkCmdPipelineBarrier((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_barrier);
+ framebuffer->swap_chain_acquired = false;
+ }
+
VkRenderPassBeginInfo render_pass_begin = {};
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin.renderPass = (VkRenderPass)p_render_pass.id;
- render_pass_begin.framebuffer = (VkFramebuffer)p_framebuffer.id;
+ render_pass_begin.framebuffer = framebuffer->vk_framebuffer;
render_pass_begin.renderArea.offset.x = p_rect.position.x;
render_pass_begin.renderArea.offset.y = p_rect.position.y;
@@ -4550,6 +4949,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 +4993,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 +5054,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 +5073,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 +5133,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 +5161,296 @@ 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 defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ if (p_data == BreadcrumbMarker::NONE) {
+ return;
+ }
+
+ if (Engine::get_singleton()->is_accurate_breadcrumbs_enabled()) {
+ // Force a full barrier so commands are not executed in parallel.
+ // This will mean that the last breadcrumb to see was actually the
+ // last (group of) command to be executed (hence, the one causing the crash).
+ VkMemoryBarrier memoryBarrier;
+ memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ memoryBarrier.pNext = nullptr;
+ memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ VK_ACCESS_INDEX_READ_BIT |
+ VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ VK_ACCESS_UNIFORM_READ_BIT |
+ VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ VK_ACCESS_SHADER_READ_BIT |
+ VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT |
+ VK_ACCESS_HOST_READ_BIT |
+ VK_ACCESS_HOST_WRITE_BIT;
+ memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
+ VK_ACCESS_INDEX_READ_BIT |
+ VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
+ VK_ACCESS_UNIFORM_READ_BIT |
+ VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+ VK_ACCESS_SHADER_READ_BIT |
+ VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT |
+ VK_ACCESS_HOST_READ_BIT |
+ VK_ACCESS_HOST_WRITE_BIT;
+
+ vkCmdPipelineBarrier(
+ (VkCommandBuffer)p_cmd_buffer.id,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ 0, 1u, &memoryBarrier, 0u, nullptr, 0u, nullptr);
+ }
+
+ // We write to a circular buffer. If you're getting barrier sync errors here,
+ // increase the value of BREADCRUMB_BUFFER_ENTRIES.
+ vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, breadcrumb_offset, sizeof(uint32_t), breadcrumb_id++);
+ vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, breadcrumb_offset + sizeof(uint32_t), sizeof(uint32_t), p_data);
+ breadcrumb_offset += sizeof(uint32_t) * 2u;
+ if (breadcrumb_offset >= BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u) {
+ breadcrumb_offset = 0u;
+ }
+#endif
+}
+
+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);
+ }
+
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, context_driver->get_driver_and_device_memory_report());
+}
+
+void RenderingDeviceDriverVulkan::print_lost_device_info() {
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ {
+ String error_msg = "Printing last known breadcrumbs in reverse order (last executed first).";
+ if (!Engine::get_singleton()->is_accurate_breadcrumbs_enabled()) {
+ error_msg += "\nSome of them might be inaccurate. Try running with --accurate-breadcrumbs for precise information.";
+ }
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, error_msg);
+ }
+
+ uint8_t *breadcrumb_ptr = nullptr;
+ VkResult map_result = VK_SUCCESS;
+
+ vmaFlushAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u);
+ vmaInvalidateAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u);
+ {
+ void *ptr = nullptr;
+ map_result = vmaMapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, &ptr);
+ breadcrumb_ptr = reinterpret_cast<uint8_t *>(ptr);
+ }
+
+ if (breadcrumb_ptr && map_result == VK_SUCCESS) {
+ uint32_t last_breadcrumb_offset = 0;
+ {
+ _err_print_error_asap("Searching last breadcrumb. We've sent up to ID: " + itos(breadcrumb_id - 1u));
+
+ // Scan the whole buffer to find the offset with the highest ID.
+ // That means that was the last one to be written.
+ //
+ // We use "breadcrumb_id - id" to account for wraparound.
+ // e.g. breadcrumb_id = 2 and id = 4294967294; then 2 - 4294967294 = 4.
+ // The one with the smallest difference is the closest to breadcrumb_id, which means it's
+ // the last written command.
+ uint32_t biggest_id = 0u;
+ uint32_t smallest_id_diff = std::numeric_limits<uint32_t>::max();
+ const uint32_t *breadcrumb_ptr32 = reinterpret_cast<const uint32_t *>(breadcrumb_ptr);
+ for (size_t i = 0u; i < BREADCRUMB_BUFFER_ENTRIES; ++i) {
+ const uint32_t id = breadcrumb_ptr32[i * 2u];
+ const uint32_t id_diff = breadcrumb_id - id;
+ if (id_diff < smallest_id_diff) {
+ biggest_id = i;
+ smallest_id_diff = id_diff;
+ }
+ }
+
+ _err_print_error_asap("Last breadcrumb ID found: " + itos(breadcrumb_ptr32[biggest_id * 2u]));
+
+ last_breadcrumb_offset = biggest_id * sizeof(uint32_t) * 2u;
+ }
+
+ const size_t entries_to_print = 8u; // Note: The value is arbitrary.
+ for (size_t i = 0u; i < entries_to_print; ++i) {
+ const uint32_t last_breadcrumb = *reinterpret_cast<uint32_t *>(breadcrumb_ptr + last_breadcrumb_offset + sizeof(uint32_t));
+ const uint32_t phase = last_breadcrumb & uint32_t(~((1 << 16) - 1));
+ const 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_asap(error_msg);
+
+ if (last_breadcrumb_offset == 0u) {
+ // Decrement last_breadcrumb_idx, wrapping underflow.
+ last_breadcrumb_offset = BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u;
+ }
+ last_breadcrumb_offset -= sizeof(uint32_t) * 2u;
+ }
+
+ vmaUnmapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle);
+ breadcrumb_ptr = nullptr;
+ } else {
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Couldn't map breadcrumb buffer. VkResult = " + itos(map_result));
+ }
+#endif
+ on_device_lost();
+}
+
+inline String RenderingDeviceDriverVulkan::get_vulkan_result(VkResult err) {
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ if (err == VK_ERROR_OUT_OF_HOST_MEMORY) {
+ return "VK_ERROR_OUT_OF_HOST_MEMORY";
+ } else if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
+ return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
+ } else if (err == VK_ERROR_DEVICE_LOST) {
+ return "VK_ERROR_DEVICE_LOST";
+ } else if (err == VK_ERROR_SURFACE_LOST_KHR) {
+ return "VK_ERROR_SURFACE_LOST_KHR";
+ } else if (err == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) {
+ return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
+ }
+#endif
+ return itos(err);
+}
+
/********************/
/**** SUBMISSION ****/
/********************/
@@ -5010,9 +5713,14 @@ 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() {
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ buffer_free(breadcrumb_buffer);
+#endif
+
while (small_allocs_pools.size()) {
HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin();
vmaDestroyPool(allocator, E->value);
@@ -5021,6 +5729,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));
}
}