From 478b0b42782a985f2fe8b485f44f222043a89449 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 5 Feb 2019 13:00:23 +0100 Subject: [PATCH] Further improve VK extension loading. Switch to VK_EXT_debug_utils (but fallback to VK_EXT_debug_report if only that is available). --- Common/Vulkan/VulkanContext.cpp | 72 +++++++++++++++++++++----- Common/Vulkan/VulkanContext.h | 18 +++---- Common/Vulkan/VulkanDebug.cpp | 59 ++++++++++++++++++++- Common/Vulkan/VulkanDebug.h | 3 +- Common/Vulkan/VulkanLoader.cpp | 76 ++++++++++++++++++++-------- Common/Vulkan/VulkanLoader.h | 35 +++++++++++-- Windows/GPU/WindowsVulkanContext.cpp | 14 ++++- android/jni/AndroidVulkanContext.cpp | 2 + 8 files changed, 225 insertions(+), 54 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 03cfb76730..ac64e2716f 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -120,9 +120,6 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { //#if defined(VK_USE_PLATFORM_XCB_KHR) // instance_extensions_enabled_.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); //#endif -//#if defined(VK_USE_PLATFORM_MIR_KHR) -// instance_extensions_enabled_.push_back(VK_KHR_MIR_SURFACE_EXTENSION_NAME); -//#endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) if (IsInstanceExtensionAvailable(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) { instance_extensions_enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); @@ -131,12 +128,21 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { #endif if (flags_ & VULKAN_FLAG_VALIDATE) { - if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { + if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { + // Enable the validation layers + for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) { + instance_layer_names_.push_back(validationLayers[i]); + device_layer_names_.push_back(validationLayers[i]); + } + instance_extensions_enabled_.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + extensionsLookup_.EXT_debug_utils = true; + } else if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) { instance_layer_names_.push_back(validationLayers[i]); device_layer_names_.push_back(validationLayers[i]); } instance_extensions_enabled_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + extensionsLookup_.EXT_debug_report = true; } else { ELOG("Validation layer extension not available - not enabling Vulkan validation."); flags_ &= ~VULKAN_FLAG_VALIDATE; @@ -195,7 +201,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return res; } - VulkanLoadInstanceFunctions(instance_); + VulkanLoadInstanceFunctions(instance_, extensionsLookup_); if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { WLOG("CheckLayers for instance failed"); // init_error_ = "Failed to validate instance layers"; @@ -604,8 +610,8 @@ VkResult VulkanContext::CreateDevice() { return VK_ERROR_INITIALIZATION_FAILED; } - VkDeviceQueueCreateInfo queue_info{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; - float queue_priorities[1] = { 1.0f }; + VkDeviceQueueCreateInfo queue_info{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; + float queue_priorities[1] = {1.0f}; queue_info.queueCount = 1; queue_info.pQueuePriorities = queue_priorities; bool found = false; @@ -618,12 +624,24 @@ VkResult VulkanContext::CreateDevice() { } assert(found); + extensionsLookup_.KHR_maintenance1 = EnableDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + extensionsLookup_.KHR_maintenance2 = EnableDeviceExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + extensionsLookup_.KHR_maintenance3 = EnableDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); + extensionsLookup_.KHR_multiview = EnableDeviceExtension(VK_KHR_MULTIVIEW_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { extensionsLookup_.KHR_get_memory_requirements2 = true; extensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); } - extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); - extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { + if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME)) { + extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); + } + } + if (EnableDeviceExtension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + extensionsLookup_.KHR_create_renderpass2 = true; + extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + } extensionsLookup_.EXT_shader_stencil_export = EnableDeviceExtension(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME); VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; @@ -640,7 +658,7 @@ VkResult VulkanContext::CreateDevice() { init_error_ = "Unable to create Vulkan device"; ELOG("Unable to create Vulkan device"); } else { - VulkanLoadDeviceFunctions(device_); + VulkanLoadDeviceFunctions(device_, extensionsLookup_); } ILOG("Device created.\n"); VulkanSetAvailable(true); @@ -662,7 +680,7 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun cb.flags = bits; cb.pfnCallback = dbgFunc; cb.pUserData = userdata; - VkResult res = dyn_vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); + VkResult res = vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); switch (res) { case VK_SUCCESS: msg_callbacks.push_back(msg_callback); @@ -676,12 +694,42 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun } void VulkanContext::DestroyDebugMsgCallback() { + if (!extensionsLookup_.EXT_debug_report) + return; while (msg_callbacks.size() > 0) { - dyn_vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); + vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); msg_callbacks.pop_back(); } } +VkResult VulkanContext::InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata) { + VkDebugUtilsMessengerCreateInfoEXT callback1{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + callback1.messageSeverity = bits; + callback1.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + callback1.pfnUserCallback = callback; + callback1.pUserData = userdata; + VkDebugUtilsMessengerEXT messenger; + VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger); + if (res != VK_SUCCESS) { + ELOG("Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); + // Do error handling for VK_ERROR_OUT_OF_MEMORY + } else { + ILOG("Debug callback registered with vkCreateDebugUtilsMessengerEXT."); + utils_callbacks.push_back(messenger); + } + return res; +} + +void VulkanContext::DestroyDebugUtilsCallback() { + if (!extensionsLookup_.EXT_debug_utils) + return; + while (utils_callbacks.size() > 0) { + vkDestroyDebugUtilsMessengerEXT(instance_, utils_callbacks.back(), nullptr); + utils_callbacks.pop_back(); + } +} + + VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) { winsys_ = winsys; winsysData1_ = data1; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 41d1cd3436..42ae79d132 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -101,17 +101,6 @@ private: std::vector callbacks_; }; -// For fast extension-enabled checks. -struct VulkanDeviceExtensions { - bool KHR_get_memory_requirements2; - bool KHR_dedicated_allocation; - bool EXT_external_memory_host; - bool KHR_get_physical_device_properties2; - bool KHR_depth_stencil_resolve; - bool EXT_shader_stencil_export; - // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. -}; - // Useful for debugging on ARM Mali. This eliminates transaction elimination // which can cause artifacts if you get barriers wrong (or if there are driver bugs). // Cost is reduced performance on some GPU architectures. @@ -175,7 +164,11 @@ public: bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); - VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr); + VkResult InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata); + void DestroyDebugUtilsCallback(); + + // Legacy reporting + VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata); void DestroyDebugMsgCallback(); VkPhysicalDevice GetPhysicalDevice(int n = 0) const { @@ -334,6 +327,7 @@ private: VulkanDeleteList globalDeleteList_; std::vector msg_callbacks; + std::vector utils_callbacks; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; VkFormat swapchainFormat_; diff --git a/Common/Vulkan/VulkanDebug.cpp b/Common/Vulkan/VulkanDebug.cpp index 81925a4653..64538196ff 100644 --- a/Common/Vulkan/VulkanDebug.cpp +++ b/Common/Vulkan/VulkanDebug.cpp @@ -56,7 +56,7 @@ const char *ObjTypeToString(VkDebugReportObjectTypeEXT type) { } } -VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) { +VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) { const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData; std::ostringstream message; @@ -103,3 +103,60 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje // keep that behavior here. return false; } + +VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) { + const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData; + std::ostringstream message; + + const char *pMessage = pCallbackData->pMessage; + int messageCode = pCallbackData->messageIdNumber; + const char *pLayerPrefix = ""; + // Ignore perf warnings for now. Could log them, so still want them registered. + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + message << "ERROR("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + message << "WARNING("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + message << "INFO("; + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + message << "VERBOSE("; + } + + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { + message << "perf"; + } else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { + message << "general"; + } else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + message << "validation"; + } + message << ":" << pCallbackData->messageIdNumber << ") " << pMessage << "\n"; + + +#ifdef _WIN32 + std::string msg = message.str(); + OutputDebugStringA(msg.c_str()); + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + if (options->breakOnError && IsDebuggerPresent()) { + DebugBreak(); + } + if (options->msgBoxOnError) { + MessageBoxA(NULL, pMessage, "Alert", MB_OK); + } + } else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + if (options->breakOnWarning && IsDebuggerPresent() && 0 == (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) { + DebugBreak(); + } + } +#endif + + // false indicates that layer should not bail-out of an + // API call that had validation failures. This may mean that the + // app dies inside the driver due to invalid parameter(s). + // That's what would happen without validation layers, so we'll + // keep that behavior here. + return false; +} diff --git a/Common/Vulkan/VulkanDebug.h b/Common/Vulkan/VulkanDebug.h index 21a4e671bb..10cb70d8ed 100644 --- a/Common/Vulkan/VulkanDebug.h +++ b/Common/Vulkan/VulkanDebug.h @@ -25,4 +25,5 @@ struct VulkanLogOptions { bool msgBoxOnError; }; -VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData); +VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData); +VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index b9e4522005..aedcfd639b 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -193,8 +193,16 @@ PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkQueuePresentKHR vkQueuePresentKHR; // And the DEBUG_REPORT extension. We dynamically load this. -PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; -PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + +PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; @@ -262,19 +270,22 @@ bool VulkanMayBeAvailable() { VkApplicationInfo info{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; std::vector devices; bool anyGood = false; - const char *instanceExtensions[1]{}; + const char *instanceExtensions[2]{}; VkInstance instance = VK_NULL_HANDLE; VkResult res; uint32_t physicalDeviceCount = 0; - uint32_t instanceExtCount = 0; + uint32_t instanceExtCount = 1; + bool surfaceExtensionFound = false; + bool platformSurfaceExtensionFound = false; std::vector instanceExts; + instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME; #ifdef _WIN32 - const char * const surfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; + const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; #elif defined(__ANDROID__) - const char *surfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; + const char *platformSurfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; #else - const char *surfaceExtension = 0; + const char *platformSurfaceExtension = 0; #endif if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) @@ -297,16 +308,18 @@ bool VulkanMayBeAvailable() { goto bail; } - if (surfaceExtension) { + if (platformSurfaceExtension) { for (auto iter : instanceExts) { - if (!strcmp(iter.extensionName, surfaceExtension)) { - instanceExtensions[0] = surfaceExtension; - ci.enabledExtensionCount = 1; + if (!strcmp(iter.extensionName, platformSurfaceExtension)) { + instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension; + platformSurfaceExtensionFound = true; break; + } else if (!strcmp(iter.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) { + surfaceExtensionFound = true; } } - if (!ci.enabledExtensionCount) { - ELOG("Surface extension not found"); + if (!platformSurfaceExtensionFound || !surfaceExtensionFound) { + ELOG("Platform surface extension not found"); goto bail; } } @@ -411,7 +424,7 @@ bool VulkanLoad() { return true; } -void VulkanLoadInstanceFunctions(VkInstance instance) { +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) { // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -570,11 +583,26 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); - dyn_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); - dyn_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); + if (enabledExtensions.KHR_get_physical_device_properties2) { + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); + } + + if (enabledExtensions.EXT_debug_report) { + LOAD_INSTANCE_FUNC(instance, vkCreateDebugReportCallbackEXT); + LOAD_INSTANCE_FUNC(instance, vkDestroyDebugReportCallbackEXT); + } + + if (enabledExtensions.EXT_debug_utils) { + LOAD_INSTANCE_FUNC(instance, vkCreateDebugUtilsMessengerEXT); + LOAD_INSTANCE_FUNC(instance, vkDestroyDebugUtilsMessengerEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdBeginDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdEndDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkCmdInsertDebugUtilsLabelEXT); + LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectNameEXT); + LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT); + } WLOG("Vulkan instance functions loaded."); } @@ -582,7 +610,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { // On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may // increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very // good for multi-device. -void VulkanLoadDeviceFunctions(VkDevice device) { +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) { WLOG("Vulkan device functions loaded."); // TODO: Move more functions VulkanLoadInstanceFunctions to here. LOAD_DEVICE_FUNC(device, vkCreateSwapchainKHR); @@ -590,9 +618,13 @@ void VulkanLoadDeviceFunctions(VkDevice device) { LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR); LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR); LOAD_DEVICE_FUNC(device, vkQueuePresentKHR); - LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); - LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); - LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + if (enabledExtensions.EXT_external_memory_host) { + LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT); + } + if (enabledExtensions.KHR_dedicated_allocation) { + LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); + LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + } } void VulkanFree() { diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 25c93efee0..3d1ccae86b 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -197,8 +197,16 @@ extern PFN_vkQueuePresentKHR vkQueuePresentKHR; // And the DEBUG_REPORT extension. Since we load this dynamically even in static // linked mode, we have to rename it :( -extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; -extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + +extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; // Assorted other extensions. extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; @@ -207,11 +215,30 @@ extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesE extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; + +// For fast extension-enabled checks. +struct VulkanDeviceExtensions { + bool EXT_debug_report; + bool EXT_debug_utils; + bool KHR_maintenance1; // required for KHR_create_renderpass2 + bool KHR_maintenance2; + bool KHR_maintenance3; + bool KHR_multiview; // required for KHR_create_renderpass2 + bool KHR_get_memory_requirements2; + bool KHR_dedicated_allocation; + bool KHR_create_renderpass2; + bool EXT_external_memory_host; + bool KHR_get_physical_device_properties2; + bool KHR_depth_stencil_resolve; + bool EXT_shader_stencil_export; + // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. +}; + // Way to do a quick check before even attempting to load. bool VulkanMayBeAvailable(); void VulkanSetAvailable(bool available); bool VulkanLoad(); -void VulkanLoadInstanceFunctions(VkInstance instance); -void VulkanLoadDeviceFunctions(VkDevice device); +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions); void VulkanFree(); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 77abd7d94b..fbbf1ce12d 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -124,8 +124,17 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m return false; } if (g_validate_) { - int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); + if (g_Vulkan->DeviceExtensions().EXT_debug_utils) { + int bits = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + g_Vulkan->InitDebugUtilsCallback(&VulkanDebugUtilsCallback, bits, &g_LogOptions); + } else { + int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + g_Vulkan->InitDebugMsgCallback(&VulkanDebugReportCallback, bits, &g_LogOptions); + } } g_Vulkan->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd); if (!g_Vulkan->InitObjects()) { @@ -160,6 +169,7 @@ void WindowsVulkanContext::Shutdown() { g_Vulkan->WaitUntilQueueIdle(); g_Vulkan->DestroyObjects(); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance(); diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 78b1211b10..f20247145c 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -160,6 +160,7 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB if (!success) { g_Vulkan->DestroyObjects(); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance(); @@ -181,6 +182,7 @@ void AndroidVulkanContext::ShutdownFromRenderThread() { void AndroidVulkanContext::Shutdown() { ILOG("Calling NativeShutdownGraphics"); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugUtilsCallback(); g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyInstance();