diff --git a/3party/vulkan_wrapper/vulkan_wrapper.h b/3party/vulkan_wrapper/vulkan_wrapper.h index 1c6e8b224b..09d7d54a81 100755 --- a/3party/vulkan_wrapper/vulkan_wrapper.h +++ b/3party/vulkan_wrapper/vulkan_wrapper.h @@ -18,6 +18,7 @@ #define VK_NO_PROTOTYPES 1 #define VK_USE_PLATFORM_ANDROID_KHR 1 +#define USE_DEBUG_EXTENTIONS 1 #include /* Initialize the Vulkan function pointer variables declared in this header. diff --git a/android/build.gradle b/android/build.gradle index b73a44fe22..c72b82bdea 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -234,6 +234,7 @@ android { java.srcDirs = ['src', '../3party/Alohalytics/src/android/java'] // assets folder is auto-generated by tools/android/update_assets.sh, so we keep all static resources in separate folders. assets.srcDirs = ['assets'] + jniLibs.srcDirs = [android.getNdkDirectory().toString() + '/sources/third_party/vulkan/src/build-android/jniLibs'] } flavorDimensions "default" diff --git a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp index 843dcf2106..fe4dc25cd8 100644 --- a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp @@ -2,6 +2,7 @@ #include "com/mapswithme/platform/Platform.hpp" +#include "drape/drape_diagnostics.hpp" #include "drape/vulkan/vulkan_utils.hpp" #include "base/assert.hpp" @@ -15,9 +16,6 @@ namespace android { namespace { -char const * kInstanceExtensions[] = {"VK_KHR_surface", "VK_KHR_android_surface"}; -char const * kDeviceExtensions[] = {"VK_KHR_swapchain"}; - class DrawVulkanContext : public dp::vulkan::VulkanBaseContext { public: @@ -67,7 +65,7 @@ AndroidVulkanContextFactory::AndroidVulkanContextFactory() return; } - VkApplicationInfo appInfo; + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pNext = nullptr; appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); @@ -77,14 +75,20 @@ AndroidVulkanContextFactory::AndroidVulkanContextFactory() appInfo.pApplicationName = "MAPS.ME"; appInfo.pEngineName = "Drape Engine"; - VkInstanceCreateInfo instanceCreateInfo; + bool enableDiagnostics = false; +#ifdef ENABLE_VULKAN_DIAGNOSTICS + enableDiagnostics = true; +#endif + m_layers = make_unique_dp(enableDiagnostics); + + VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pNext = nullptr; instanceCreateInfo.pApplicationInfo = &appInfo; - instanceCreateInfo.enabledExtensionCount = ARRAY_SIZE(kInstanceExtensions); - instanceCreateInfo.ppEnabledExtensionNames = kInstanceExtensions; - instanceCreateInfo.enabledLayerCount = 0; - instanceCreateInfo.ppEnabledLayerNames = nullptr; + instanceCreateInfo.enabledExtensionCount = m_layers->GetInstanceExtensionsCount(); + instanceCreateInfo.ppEnabledExtensionNames = m_layers->GetInstanceExtensions(); + instanceCreateInfo.enabledLayerCount = m_layers->GetInstanceLayersCount(); + instanceCreateInfo.ppEnabledLayerNames = m_layers->GetInstanceLayers(); VkResult statusCode; statusCode = vkCreateInstance(&instanceCreateInfo, nullptr, &m_vulkanInstance); @@ -135,8 +139,11 @@ AndroidVulkanContextFactory::AndroidVulkanContextFactory() return; } + if (!m_layers->Initialize(m_vulkanInstance, m_gpu)) + return; + float priorities[] = {1.0f}; - VkDeviceQueueCreateInfo queueCreateInfo; + VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.pNext = nullptr; queueCreateInfo.flags = 0; @@ -144,15 +151,15 @@ AndroidVulkanContextFactory::AndroidVulkanContextFactory() queueCreateInfo.queueFamilyIndex = queueFamilyIndex; queueCreateInfo.pQueuePriorities = priorities; - VkDeviceCreateInfo deviceCreateInfo; + VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.pNext = nullptr; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.enabledLayerCount = 0; - deviceCreateInfo.ppEnabledLayerNames = nullptr; - deviceCreateInfo.enabledExtensionCount = ARRAY_SIZE(kDeviceExtensions); - deviceCreateInfo.ppEnabledExtensionNames = kDeviceExtensions; + deviceCreateInfo.enabledLayerCount = m_layers->GetDeviceLayersCount(); + deviceCreateInfo.ppEnabledLayerNames = m_layers->GetDeviceLayers(); + deviceCreateInfo.enabledExtensionCount = m_layers->GetDeviceExtensionsCount(); + deviceCreateInfo.ppEnabledExtensionNames = m_layers->GetDeviceExtensions(); deviceCreateInfo.pEnabledFeatures = nullptr; statusCode = vkCreateDevice(m_gpu, &deviceCreateInfo, nullptr, &m_device); @@ -168,6 +175,8 @@ AndroidVulkanContextFactory::AndroidVulkanContextFactory() AndroidVulkanContextFactory::~AndroidVulkanContextFactory() { + m_layers->Uninitialize(m_vulkanInstance); + if (m_device != nullptr) vkDestroyDevice(m_device, nullptr); @@ -190,7 +199,7 @@ void AndroidVulkanContextFactory::SetSurface(JNIEnv * env, jobject jsurface) return; } - VkAndroidSurfaceCreateInfoKHR createInfo; + VkAndroidSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; createInfo.flags = 0; @@ -219,7 +228,7 @@ void AndroidVulkanContextFactory::SetSurface(JNIEnv * env, jobject jsurface) bool AndroidVulkanContextFactory::QuerySurfaceSize() { - VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkSurfaceCapabilitiesKHR surfaceCapabilities = {}; auto statusCode = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpu, m_surface, &surfaceCapabilities); if (statusCode != VK_SUCCESS) diff --git a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp index bbae3047e3..0010ae1f57 100644 --- a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp @@ -4,6 +4,7 @@ #include "drape/graphics_context_factory.hpp" #include "drape/vulkan/vulkan_base_context.hpp" +#include "drape/vulkan/vulkan_layers.hpp" #include "drape/pointers.hpp" #include @@ -40,6 +41,7 @@ private: bool QuerySurfaceSize(); VkInstance m_vulkanInstance = nullptr; + drape_ptr m_layers; VkPhysicalDevice m_gpu = nullptr; VkDevice m_device = nullptr; drape_ptr m_drawContext; diff --git a/drape/CMakeLists.txt b/drape/CMakeLists.txt index c1cdc7b681..a3300800d8 100644 --- a/drape/CMakeLists.txt +++ b/drape/CMakeLists.txt @@ -152,6 +152,8 @@ append( SRC vulkan/vulkan_base_context.cpp vulkan/vulkan_base_context.hpp + vulkan/vulkan_layers.cpp + vulkan/vulkan_layers.hpp vulkan/vulkan_utils.cpp vulkan/vulkan_utils.hpp ) diff --git a/drape/drape_diagnostics.hpp b/drape/drape_diagnostics.hpp index 6d64b6a89e..f008fd5a3b 100644 --- a/drape/drape_diagnostics.hpp +++ b/drape/drape_diagnostics.hpp @@ -25,3 +25,5 @@ //#define TRACK_GLYPH_USAGE #endif + +#define ENABLE_VULKAN_DIAGNOSTICS diff --git a/drape/vulkan/vulkan_layers.cpp b/drape/vulkan/vulkan_layers.cpp new file mode 100755 index 0000000000..f01434304d --- /dev/null +++ b/drape/vulkan/vulkan_layers.cpp @@ -0,0 +1,456 @@ +#include "drape/vulkan/vulkan_layers.hpp" + +#include "drape/vulkan/vulkan_utils.hpp" + +#include "base/macros.hpp" + +#include +#include + +namespace dp +{ +namespace vulkan +{ +namespace +{ +char const * kDebugReportExtension = "VK_EXT_debug_report"; + +char const * const kInstanceExtensions[] = +{ + "VK_KHR_surface", + "VK_KHR_android_surface", + kDebugReportExtension, +}; + +char const * const kDeviceExtensions[] = +{ + "VK_KHR_swapchain" +}; + +// DO NOT reorder. The order matters here. +char const * const kValidationLayers[] = +{ + "VK_LAYER_GOOGLE_threading", + "VK_LAYER_LUNARG_device_limits", + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_image", + "VK_LAYER_LUNARG_object_tracker", + "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_swapchain", + "VK_LAYER_GOOGLE_unique_objects", +}; + +std::vector CheckLayers(std::vector const & props) +{ + std::vector result; + result.reserve(props.size()); + for (uint32_t i = 0; i < ARRAY_SIZE(kValidationLayers); ++i) + { + auto const it = std::find_if(props.begin(), props.end(), + [i](VkLayerProperties const & p) + { + return strcmp(kValidationLayers[i], p.layerName) == 0; + }); + if (it != props.end()) + result.push_back(kValidationLayers[i]); + } + return result; +} + +std::vector CheckExtensions(std::vector const & props, + bool enableDiagnostics, char const * const * extensions, + uint32_t extensionsCount) +{ + std::vector result; + result.reserve(props.size()); + for (uint32_t i = 0; i < extensionsCount; ++i) + { + if (!enableDiagnostics && strcmp(extensions[i], kDebugReportExtension) == 0) + continue; + + auto const it = std::find_if(props.begin(), props.end(), + [i, extensions](VkExtensionProperties const & p) + { + return strcmp(extensions[i], p.extensionName) == 0; + }); + if (it != props.end()) + result.push_back(extensions[i]); + } + return result; +} + +std::string GetReportObjectTypeString(VkDebugReportObjectTypeEXT objectType) +{ + switch (objectType) + { + case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT: return "UNKNOWN"; + case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: return "INSTANCE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: return "PHYSICAL_DEVICE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: return "DEVICE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: return "QUEUE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: return "SEMAPHORE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: return "COMMAND_BUFFER"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: return "FENCE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: return "DEVICE_MEMORY"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: return "BUFFER"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: return "IMAGE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: return "EVENT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: return "QUERY"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: return "BUFFER_VIEW"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: return "IMAGE_VIEW"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: return "SHADER_MODULE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: return "PIPELINE_CACHE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: return "PIPELINE_LAYOUT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: return "RENDER_PASS"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: return "PIPELINE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: return "DESCRIPTOR_SET_LAYOUT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: return "SAMPLER"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: return "DESCRIPTOR_POOL"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: return "DESCRIPTOR_SET"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: return "FRAMEBUFFER"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: return "COMMAND_POOL"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: return "SURFACE_KHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: return "SWAPCHAIN_KHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT: + return "DEBUG_REPORT_CALLBACK_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT: return "DISPLAY_KHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT: return "DISPLAY_MODE_KHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT: return "OBJECT_TABLE_NVX"; + case VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT: + return "INDIRECT_COMMANDS_LAYOUT_NVX"; + case VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT: return "VALIDATION_CACHE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT: return "SAMPLER_YCBCR_CONVERSION"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT: + return "DESCRIPTOR_UPDATE_TEMPLATE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT: + return "ACCELERATION_STRUCTURE_NV"; + case VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT: return "RANGE_SIZE"; + case VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT: return "MAX_ENUM"; + } + UNREACHABLE(); + return {}; +} + +bool HasLayerOrExtension(char const * name, std::vector const & collection) +{ + return collection.end() != std::find_if(collection.begin(), collection.end(), + [name](char const * v) { return strcmp(name, v) == 0; }); +} +} // namespace + +VkBool32 VKAPI_PTR DebugReportCallbackImpl(VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, uint64_t object, + size_t location, int32_t messageCode, + const char * pLayerPrefix, const char * pMessage, + void * pUserData) +{ + if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) + { + LOG(LINFO, ("Vulkan Diagnostics [", pLayerPrefix, "] [", GetReportObjectTypeString(objectType), + "] [OBJ:", object, "LOC:", location, "]:", pMessage)); + } + + if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) + { + LOG(LWARNING, ("Vulkan Diagnostics [", pLayerPrefix, "] [", GetReportObjectTypeString(objectType), + "] [OBJ:", object, "LOC:", location, "]:", pMessage)); + } + + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) + { + LOG(LERROR, ("Vulkan Diagnostics [", pLayerPrefix, "] [", GetReportObjectTypeString(objectType), + "] [OBJ:", object, "LOC:", location, "]:", pMessage)); + } + + if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) + { + LOG(LDEBUG, ("Vulkan Diagnostics [", pLayerPrefix, "] [", GetReportObjectTypeString(objectType), + "] [OBJ:", object, "LOC:", location, "]:", pMessage)); + } + + if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) + { + LOG(LWARNING, ("Vulkan Diagnostics (Performance) [", pLayerPrefix, "] [", + GetReportObjectTypeString(objectType), "] [OBJ:", object, "LOC:", location, + "]:", pMessage)); + } + + return VK_FALSE; +} + +Layers::Layers(bool enableDiagnostics) + : m_enableDiagnostics(enableDiagnostics) + , m_vkCreateDebugReportCallbackEXT(vkCreateDebugReportCallbackEXT) + , m_vkDestroyDebugReportCallbackEXT(vkDestroyDebugReportCallbackEXT) + , m_vkDebugReportMessageEXT(vkDebugReportMessageEXT) +{ + if (m_enableDiagnostics) + { + // Get instance layers count. + uint32_t instLayerCount = 0; + auto statusCode = vkEnumerateInstanceLayerProperties(&instLayerCount, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceLayerProperties, statusCode); + return; + } + + // Enumerate instance layers. + std::vector layerProperties; + if (instLayerCount != 0) + { + layerProperties.resize(instLayerCount); + statusCode = vkEnumerateInstanceLayerProperties(&instLayerCount, layerProperties.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceLayerProperties, statusCode); + return; + } + m_instanceLayers = CheckLayers(layerProperties); + + for (auto layer : m_instanceLayers) + LOG(LDEBUG, ("Vulkan instance layer prepared", layer)); + } + } + + // Get instance extensions count. + uint32_t instExtensionsCount = 0; + auto statusCode = vkEnumerateInstanceExtensionProperties(nullptr, &instExtensionsCount, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceExtensionProperties, statusCode); + return; + } + + // Enumerate instance extensions. + std::vector extensionsProperties; + if (instExtensionsCount != 0) + { + extensionsProperties.resize(instExtensionsCount); + statusCode = vkEnumerateInstanceExtensionProperties(nullptr, &instExtensionsCount, + extensionsProperties.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceExtensionProperties, statusCode); + return; + } + } + + // Enumerate instance extensions for each layer. + for (auto layerName : m_instanceLayers) + { + uint32_t cnt = 0; + statusCode = vkEnumerateInstanceExtensionProperties(layerName, &cnt, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceExtensionProperties, statusCode); + return; + } + if (cnt == 0) + continue; + + std::vector props(cnt); + statusCode = vkEnumerateInstanceExtensionProperties(layerName, &cnt, props.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateInstanceExtensionProperties, statusCode); + return; + } + extensionsProperties.insert(extensionsProperties.end(), props.begin(), props.end()); + } + + m_instanceExtensions = CheckExtensions(extensionsProperties, m_enableDiagnostics, + kInstanceExtensions, ARRAY_SIZE(kInstanceExtensions)); + + for (auto ext : m_instanceExtensions) + LOG(LDEBUG, ("Vulkan instance extension prepared", ext)); + + if (m_enableDiagnostics && !HasLayerOrExtension(kDebugReportExtension, m_instanceExtensions)) + LOG(LWARNING, ("Vulkan diagnostics in not available on this device.")); +} + +uint32_t Layers::GetInstanceLayersCount() const +{ + if (!m_enableDiagnostics) + return 0; + + return static_cast(m_instanceLayers.size()); +} + +char const * const * Layers::GetInstanceLayers() const +{ + if (!m_enableDiagnostics) + return nullptr; + + return m_instanceLayers.data(); +} + +uint32_t Layers::GetInstanceExtensionsCount() const +{ + return static_cast(m_instanceExtensions.size()); +} + +char const * const * Layers::GetInstanceExtensions() const +{ + return m_instanceExtensions.data(); +} + +bool Layers::Initialize(VkInstance instance, VkPhysicalDevice physicalDevice) +{ + if (m_enableDiagnostics) + { + // Get device layers count. + uint32_t devLayerCount = 0; + auto statusCode = vkEnumerateDeviceLayerProperties(physicalDevice, &devLayerCount, + nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceLayerProperties, statusCode); + return false; + } + + // Enumerate device layers. + std::vector layerProperties; + if (devLayerCount != 0) + { + layerProperties.resize(devLayerCount); + statusCode = vkEnumerateDeviceLayerProperties(physicalDevice, &devLayerCount, + layerProperties.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceLayerProperties, statusCode); + return false; + } + m_deviceLayers = CheckLayers(layerProperties); + + for (auto layer : m_deviceLayers) + LOG(LDEBUG, ("Vulkan device layer prepared", layer)); + } + } + + // Get device extensions count. + uint32_t devExtensionsCount = 0; + auto statusCode = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, + &devExtensionsCount, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceExtensionProperties, statusCode); + return false; + } + + // Enumerate device extensions. + std::vector extensionsProperties; + if (devExtensionsCount != 0) + { + extensionsProperties.resize(devExtensionsCount); + statusCode = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, + &devExtensionsCount, + extensionsProperties.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceExtensionProperties, statusCode); + return false; + } + } + + // Enumerate device extensions for each layer. + for (auto layerName : m_deviceLayers) + { + uint32_t cnt = 0; + statusCode = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, + &cnt, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceExtensionProperties, statusCode); + return false; + } + if (cnt == 0) + continue; + + std::vector props(cnt); + statusCode = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, + &cnt, props.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumerateDeviceExtensionProperties, statusCode); + return false; + } + extensionsProperties.insert(extensionsProperties.end(), props.begin(), props.end()); + } + + m_deviceExtensions = CheckExtensions(extensionsProperties, m_enableDiagnostics, + kDeviceExtensions, ARRAY_SIZE(kDeviceExtensions)); + for (auto ext : m_deviceExtensions) + LOG(LDEBUG, ("Vulkan device extension prepared", ext)); + + if (m_enableDiagnostics && HasLayerOrExtension(kDebugReportExtension, m_instanceExtensions)) + { + if (m_vkCreateDebugReportCallbackEXT == nullptr) + { + m_vkCreateDebugReportCallbackEXT = + (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); + m_vkDestroyDebugReportCallbackEXT = + (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); + m_vkDebugReportMessageEXT = + (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT"); + } + + if (m_vkCreateDebugReportCallbackEXT == nullptr) + { + LOG_ERROR_VK("Function vkCreateDebugReportCallbackEXT is not found."); + return false; + } + + VkDebugReportCallbackCreateInfoEXT dbgInfo = {}; + dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + dbgInfo.pNext = nullptr; + dbgInfo.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | + VK_DEBUG_REPORT_ERROR_BIT_EXT; + dbgInfo.pfnCallback = DebugReportCallbackImpl; + dbgInfo.pUserData = nullptr; + statusCode = m_vkCreateDebugReportCallbackEXT(instance, &dbgInfo, nullptr, + &m_reportCallback); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkCreateDebugReportCallbackEXT, statusCode); + return false; + } + } + + return true; +} + +void Layers::Uninitialize(VkInstance instance) +{ + if (m_reportCallback != 0 && m_vkDestroyDebugReportCallbackEXT != nullptr) + m_vkDestroyDebugReportCallbackEXT(instance, m_reportCallback, nullptr); +} + +uint32_t Layers::GetDeviceLayersCount() const +{ + if (!m_enableDiagnostics) + return 0; + + return static_cast(m_deviceLayers.size()); +} + +char const * const * Layers::GetDeviceLayers() const +{ + if (!m_enableDiagnostics) + return nullptr; + + return m_deviceLayers.data(); +} + +uint32_t Layers::GetDeviceExtensionsCount() const +{ + return static_cast(m_deviceExtensions.size()); +} + +char const * const * Layers::GetDeviceExtensions() const +{ + return m_deviceExtensions.data(); +} +} // namespace vulkan +} // namespace dp diff --git a/drape/vulkan/vulkan_layers.hpp b/drape/vulkan/vulkan_layers.hpp new file mode 100755 index 0000000000..ee7ec65b26 --- /dev/null +++ b/drape/vulkan/vulkan_layers.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include +#include + +namespace dp +{ +namespace vulkan +{ +class Layers +{ +public: + explicit Layers(bool enableDiagnostics); + + // These method are available before initialization. + uint32_t GetInstanceLayersCount() const; + char const * const * GetInstanceLayers() const; + uint32_t GetInstanceExtensionsCount() const; + char const * const * GetInstanceExtensions() const; + + bool Initialize(VkInstance instance, VkPhysicalDevice physicalDevice); + void Uninitialize(VkInstance instance); + + // These method are available after initialization. + uint32_t GetDeviceLayersCount() const; + char const * const * GetDeviceLayers() const; + uint32_t GetDeviceExtensionsCount() const; + char const * const * GetDeviceExtensions() const; + +private: + bool const m_enableDiagnostics; + + std::vector m_instanceLayers; + std::vector m_instanceExtensions; + + std::vector m_deviceLayers; + std::vector m_deviceExtensions; + + VkDebugReportCallbackEXT m_reportCallback = 0; + + PFN_vkCreateDebugReportCallbackEXT m_vkCreateDebugReportCallbackEXT = nullptr; + PFN_vkDestroyDebugReportCallbackEXT m_vkDestroyDebugReportCallbackEXT = nullptr; + PFN_vkDebugReportMessageEXT m_vkDebugReportMessageEXT = nullptr; +}; +} // namespace vulkan +} // namespace dp diff --git a/drape/vulkan/vulkan_utils.cpp b/drape/vulkan/vulkan_utils.cpp index 11e5a3bff9..a7bf25aba5 100644 --- a/drape/vulkan/vulkan_utils.cpp +++ b/drape/vulkan/vulkan_utils.cpp @@ -1,5 +1,7 @@ #include "drape/vulkan/vulkan_utils.hpp" +#include "base/assert.hpp" + namespace dp { namespace vulkan @@ -13,7 +15,7 @@ std::string GetVulkanResultString(VkResult result) case VK_TIMEOUT: return "VK_TIMEOUT"; case VK_EVENT_SET: return "VK_EVENT_SET"; case VK_EVENT_RESET: return "VK_EVENT_RESET"; - case VK_INCOMPLETE: return "VK_INCOMPLETE/VK_RESULT_END_RANGE"; + case VK_INCOMPLETE: return "VK_INCOMPLETE"; case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; @@ -25,7 +27,7 @@ std::string GetVulkanResultString(VkResult result) case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; - case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL/VK_RESULT_BEGIN_RANGE"; + case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL"; case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; @@ -42,6 +44,7 @@ std::string GetVulkanResultString(VkResult result) case VK_RESULT_RANGE_SIZE: return "VK_RESULT_RANGE_SIZE"; case VK_RESULT_MAX_ENUM: return "VK_RESULT_MAX_ENUM"; } + UNREACHABLE(); return "Unknown result"; } } // namespace vulkan