diff --git a/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.cpp b/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.cpp index 9559d4db6a..84b9220632 100644 --- a/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.cpp +++ b/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.cpp @@ -2,274 +2,16 @@ #include "app/organicmaps/platform/AndroidPlatform.hpp" -#include "drape/drape_diagnostics.hpp" -#include "drape/support_manager.hpp" -#include "drape/vulkan/vulkan_pipeline.hpp" -#include "drape/vulkan/vulkan_utils.hpp" - #include "base/assert.hpp" #include "base/logging.hpp" #include "base/macros.hpp" #include "base/src_point.hpp" -#include -#include - namespace android { -namespace -{ -class DrawVulkanContext : public dp::vulkan::VulkanBaseContext -{ -public: - DrawVulkanContext(VkInstance vulkanInstance, VkPhysicalDevice gpu, - VkPhysicalDeviceProperties const & gpuProperties, VkDevice device, - uint32_t renderingQueueFamilyIndex, - ref_ptr objectManager, uint32_t appVersionCode, - bool hasPartialTextureUpdates) - : dp::vulkan::VulkanBaseContext( - vulkanInstance, gpu, gpuProperties, device, renderingQueueFamilyIndex, objectManager, - make_unique_dp(device, appVersionCode), - hasPartialTextureUpdates) - { - VkQueue queue; - vkGetDeviceQueue(device, renderingQueueFamilyIndex, 0, &queue); - SetRenderingQueue(queue); - CreateCommandPool(); - } - - void MakeCurrent() override - { - m_objectManager->RegisterThread(dp::vulkan::VulkanObjectManager::Frontend); - } -}; - -class UploadVulkanContext : public dp::vulkan::VulkanBaseContext -{ -public: - UploadVulkanContext(VkInstance vulkanInstance, VkPhysicalDevice gpu, - VkPhysicalDeviceProperties const & gpuProperties, VkDevice device, - uint32_t renderingQueueFamilyIndex, - ref_ptr objectManager, - bool hasPartialTextureUpdates) - : dp::vulkan::VulkanBaseContext(vulkanInstance, gpu, gpuProperties, device, - renderingQueueFamilyIndex, objectManager, - nullptr /* pipeline */, hasPartialTextureUpdates) - {} - - void MakeCurrent() override - { - m_objectManager->RegisterThread(dp::vulkan::VulkanObjectManager::Backend); - } - - void Present() override {} - - void Resize(int w, int h) override {} - void SetFramebuffer(ref_ptr framebuffer) override {} - void Init(dp::ApiVersion apiVersion) override - { - CHECK_EQUAL(apiVersion, dp::ApiVersion::Vulkan, ()); - } - - void SetClearColor(dp::Color const & color) override {} - void Clear(uint32_t clearBits, uint32_t storeBits) override {} - void Flush() override {} - void SetDepthTestEnabled(bool enabled) override {} - void SetDepthTestFunction(dp::TestFunction depthFunction) override {} - void SetStencilTestEnabled(bool enabled) override {} - void SetStencilFunction(dp::StencilFace face, - dp::TestFunction stencilFunction) override {} - void SetStencilActions(dp::StencilFace face, - dp::StencilAction stencilFailAction, - dp::StencilAction depthFailAction, - dp::StencilAction passAction) override {} -}; -} // namespace - AndroidVulkanContextFactory::AndroidVulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM) -{ - if (InitVulkan() == 0) - { - LOG_ERROR_VK("Could not initialize Vulkan library."); - return; - } - - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pNext = nullptr; - appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.applicationVersion = appVersionCode; - appInfo.engineVersion = appVersionCode; - appInfo.pApplicationName = "OMaps"; - appInfo.pEngineName = "Drape Engine"; - - 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 = m_layers->GetInstanceExtensionsCount(); - instanceCreateInfo.ppEnabledExtensionNames = m_layers->GetInstanceExtensions(); - instanceCreateInfo.enabledLayerCount = m_layers->GetInstanceLayersCount(); - instanceCreateInfo.ppEnabledLayerNames = m_layers->GetInstanceLayers(); - - // Enable extra validation features. - VkValidationFeaturesEXT validationFeatures = {}; - const VkValidationFeatureEnableEXT validationFeaturesEnabled[] = { - VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT}; - if (m_layers->IsValidationFeaturesEnabled()) - { - validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - validationFeatures.pNext = nullptr; - validationFeatures.enabledValidationFeatureCount = ARRAY_SIZE(validationFeaturesEnabled), - validationFeatures.pEnabledValidationFeatures = validationFeaturesEnabled; - - instanceCreateInfo.pNext = &validationFeatures; - } - - VkResult statusCode; - statusCode = vkCreateInstance(&instanceCreateInfo, nullptr, &m_vulkanInstance); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkCreateInstance, statusCode); - return; - } - - uint32_t gpuCount = 0; - statusCode = vkEnumeratePhysicalDevices(m_vulkanInstance, &gpuCount, nullptr); - if (statusCode != VK_SUCCESS || gpuCount == 0) - { - LOG_ERROR_VK_CALL(vkEnumeratePhysicalDevices, statusCode); - return; - } - - std::vector tmpGpus(gpuCount); - statusCode = vkEnumeratePhysicalDevices(m_vulkanInstance, &gpuCount, tmpGpus.data()); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkEnumeratePhysicalDevices, statusCode); - return; - } - m_gpu = tmpGpus[0]; - - VkPhysicalDeviceProperties gpuProperties; - vkGetPhysicalDeviceProperties(m_gpu, &gpuProperties); - dp::SupportManager::Version apiVersion{VK_VERSION_MAJOR(gpuProperties.apiVersion), - VK_VERSION_MINOR(gpuProperties.apiVersion), - VK_VERSION_PATCH(gpuProperties.apiVersion)}; - dp::SupportManager::Version driverVersion{VK_VERSION_MAJOR(gpuProperties.driverVersion), - VK_VERSION_MINOR(gpuProperties.driverVersion), - VK_VERSION_PATCH(gpuProperties.driverVersion)}; - if (dp::SupportManager::Instance().IsVulkanForbidden(gpuProperties.deviceName, apiVersion, driverVersion, isCustomROM)) - { - LOG_ERROR_VK("GPU/Driver configuration is not supported."); - return; - } - - uint32_t queueFamilyCount; - vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, nullptr); - if (queueFamilyCount == 0) - { - LOG_ERROR_VK("Any queue family wasn't found."); - return; - } - - std::vector queueFamilyProperties(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, - queueFamilyProperties.data()); - - uint32_t renderingQueueFamilyIndex = 0; - for (; renderingQueueFamilyIndex < queueFamilyCount; ++renderingQueueFamilyIndex) - { - if (queueFamilyProperties[renderingQueueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) - break; - } - if (renderingQueueFamilyIndex == queueFamilyCount) - { - LOG_ERROR_VK("Any queue family with VK_QUEUE_GRAPHICS_BIT wasn't found."); - return; - } - - if (!dp::vulkan::VulkanFormatUnpacker::Init(m_gpu)) - return; - - if (!m_layers->Initialize(m_vulkanInstance, m_gpu)) - return; - - float priorities[] = {1.0f}; - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.pNext = nullptr; - queueCreateInfo.flags = 0; - queueCreateInfo.queueCount = 1; - queueCreateInfo.queueFamilyIndex = renderingQueueFamilyIndex; - queueCreateInfo.pQueuePriorities = priorities; - - VkDeviceCreateInfo deviceCreateInfo = {}; - VkPhysicalDeviceFeatures enabledFeatures = {}; - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.pNext = nullptr; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.enabledLayerCount = m_layers->GetDeviceLayersCount(); - deviceCreateInfo.ppEnabledLayerNames = m_layers->GetDeviceLayers(); - deviceCreateInfo.enabledExtensionCount = m_layers->GetDeviceExtensionsCount(); - deviceCreateInfo.ppEnabledExtensionNames = m_layers->GetDeviceExtensions(); - deviceCreateInfo.pEnabledFeatures = nullptr; - if (enableDiagnostics) - { - enabledFeatures.robustBufferAccess = VK_TRUE; - deviceCreateInfo.pEnabledFeatures = &enabledFeatures; - } - - statusCode = vkCreateDevice(m_gpu, &deviceCreateInfo, nullptr, &m_device); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkCreateDevice, statusCode); - return; - } - - VkPhysicalDeviceMemoryProperties memoryProperties; - vkGetPhysicalDeviceMemoryProperties(m_gpu, &memoryProperties); - m_objectManager = make_unique_dp(m_device, gpuProperties.limits, - memoryProperties, - renderingQueueFamilyIndex); - - bool const hasPartialTextureUpdates = - !dp::SupportManager::Instance().IsVulkanTexturePartialUpdateBuggy( - sdkVersion, gpuProperties.deviceName, apiVersion, driverVersion); - - m_drawContext = make_unique_dp( - m_vulkanInstance, m_gpu, gpuProperties, m_device, renderingQueueFamilyIndex, - make_ref(m_objectManager), appVersionCode, hasPartialTextureUpdates); - m_uploadContext = make_unique_dp( - m_vulkanInstance, m_gpu, gpuProperties, m_device, renderingQueueFamilyIndex, - make_ref(m_objectManager), hasPartialTextureUpdates); -} - -AndroidVulkanContextFactory::~AndroidVulkanContextFactory() -{ - m_drawContext.reset(); - m_uploadContext.reset(); - m_objectManager.reset(); - - if (m_device != nullptr) - { - vkDeviceWaitIdle(m_device); - vkDestroyDevice(m_device, nullptr); - } - - if (m_vulkanInstance != nullptr) - { - m_layers->Uninitialize(m_vulkanInstance); - vkDestroyInstance(m_vulkanInstance, nullptr); - } -} + : dp::vulkan::VulkanContextFactory(appVersionCode, sdkVersion, isCustomROM) +{} void AndroidVulkanContextFactory::SetSurface(JNIEnv * env, jobject jsurface) { @@ -327,56 +69,6 @@ void AndroidVulkanContextFactory::SetVulkanSurface() m_windowSurfaceValid = true; } -bool AndroidVulkanContextFactory::QuerySurfaceSize() -{ - auto statusCode = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpu, m_surface, - &m_surfaceCapabilities); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, statusCode); - return false; - } - - uint32_t formatCount = 0; - statusCode = vkGetPhysicalDeviceSurfaceFormatsKHR(m_gpu, m_surface, &formatCount, nullptr); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, statusCode); - return false; - } - - std::vector formats(formatCount); - statusCode = vkGetPhysicalDeviceSurfaceFormatsKHR(m_gpu, m_surface, &formatCount, formats.data()); - if (statusCode != VK_SUCCESS) - { - LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, statusCode); - return false; - } - - uint32_t chosenFormat; - for (chosenFormat = 0; chosenFormat < formatCount; chosenFormat++) - { - if (formats[chosenFormat].format == VK_FORMAT_R8G8B8A8_UNORM) - break; - } - if (chosenFormat == formatCount) - { - LOG_ERROR_VK("Any supported surface format wasn't found."); - return false; - } - - if (!(m_surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)) - { - LOG_ERROR_VK("Alpha channel is not supported."); - return false; - } - - m_surfaceFormat = formats[chosenFormat]; - m_surfaceWidth = static_cast(m_surfaceCapabilities.currentExtent.width); - m_surfaceHeight = static_cast(m_surfaceCapabilities.currentExtent.height); - return true; -} - void AndroidVulkanContextFactory::ResetSurface(bool allowPipelineDump) { ResetVulkanSurface(allowPipelineDump); @@ -426,51 +118,8 @@ void AndroidVulkanContextFactory::ChangeSurface(JNIEnv * env, jobject jsurface, LOG(LINFO, ("Surface changed", m_surfaceWidth, m_surfaceHeight)); } -bool AndroidVulkanContextFactory::IsVulkanSupported() const -{ - return m_vulkanInstance != nullptr && m_gpu != nullptr && m_device != nullptr; -} - bool AndroidVulkanContextFactory::IsValid() const { return IsVulkanSupported() && m_windowSurfaceValid; } - -int AndroidVulkanContextFactory::GetWidth() const -{ - ASSERT(IsValid(), ()); - return m_surfaceWidth; -} - -int AndroidVulkanContextFactory::GetHeight() const -{ - ASSERT(IsValid(), ()); - return m_surfaceHeight; -} - -dp::GraphicsContext * AndroidVulkanContextFactory::GetDrawContext() -{ - return m_drawContext.get(); -} - -dp::GraphicsContext * AndroidVulkanContextFactory::GetResourcesUploadContext() -{ - return m_uploadContext.get(); -} - -bool AndroidVulkanContextFactory::IsDrawContextCreated() const -{ - return m_drawContext != nullptr; -} - -bool AndroidVulkanContextFactory::IsUploadContextCreated() const -{ - return m_uploadContext != nullptr; -} - -void AndroidVulkanContextFactory::SetPresentAvailable(bool available) -{ - if (m_drawContext) - m_drawContext->SetPresentAvailable(available); -} } // namespace android diff --git a/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.hpp b/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.hpp index 35d16f8fb6..b98dc4c04e 100644 --- a/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.hpp +++ b/android/app/src/main/cpp/app/organicmaps/vulkan/android_vulkan_context_factory.hpp @@ -2,11 +2,7 @@ #include "app/organicmaps/core/jni_helper.hpp" -#include "drape/graphics_context_factory.hpp" -#include "drape/vulkan/vulkan_base_context.hpp" -#include "drape/vulkan/vulkan_object_manager.hpp" -#include "drape/vulkan/vulkan_layers.hpp" -#include "drape/pointers.hpp" +#include "drape/vulkan/vulkan_context_factory.hpp" #include @@ -15,48 +11,22 @@ namespace android { -class AndroidVulkanContextFactory : public dp::GraphicsContextFactory +class AndroidVulkanContextFactory : public dp::vulkan::VulkanContextFactory { public: AndroidVulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM); - ~AndroidVulkanContextFactory(); - bool IsVulkanSupported() const; bool IsValid() const; - dp::GraphicsContext * GetDrawContext() override; - dp::GraphicsContext * GetResourcesUploadContext() override; - bool IsDrawContextCreated() const override; - bool IsUploadContextCreated() const override; - void SetPresentAvailable(bool available) override; - void SetSurface(JNIEnv * env, jobject jsurface); void ResetSurface(bool allowPipelineDump); void ChangeSurface(JNIEnv * env, jobject jsurface, int w, int h); - int GetWidth() const; - int GetHeight() const; - private: void SetVulkanSurface(); void ResetVulkanSurface(bool allowPipelineDump); - bool QuerySurfaceSize(); - - VkInstance m_vulkanInstance = nullptr; - drape_ptr m_layers; - VkPhysicalDevice m_gpu = nullptr; - VkDevice m_device = nullptr; - drape_ptr m_objectManager; - drape_ptr m_drawContext; - drape_ptr m_uploadContext; ANativeWindow * m_nativeWindow = nullptr; bool m_windowSurfaceValid = false; - VkSurfaceKHR m_surface = 0; - VkSurfaceFormatKHR m_surfaceFormat; - VkSurfaceCapabilitiesKHR m_surfaceCapabilities; - - int m_surfaceWidth = 0; - int m_surfaceHeight = 0; }; } // namespace android diff --git a/drape/CMakeLists.txt b/drape/CMakeLists.txt index 1d74a250b0..945fe08f99 100644 --- a/drape/CMakeLists.txt +++ b/drape/CMakeLists.txt @@ -107,9 +107,10 @@ set(DRAPE_TESTABLE_SRC viewport.cpp viewport.hpp visual_scale.hpp - # TODO: Why Vulkan is added on all platforms, even on iOS and Mac? vulkan/vulkan_base_context.cpp vulkan/vulkan_base_context.hpp + vulkan/vulkan_context_factory.cpp + vulkan/vulkan_context_factory.hpp vulkan/vulkan_gpu_buffer_impl.cpp vulkan/vulkan_gpu_buffer_impl.hpp vulkan/vulkan_gpu_program.hpp @@ -133,12 +134,8 @@ set(DRAPE_TESTABLE_SRC vulkan/vulkan_vertex_array_buffer_impl.cpp ) -set(SRC ${DRAPE_TESTABLE_SRC} gl_functions.cpp) - -if (PLATFORM_IPHONE) - append(SRC - hw_texture_ios.hpp - hw_texture_ios.mm +if (PLATFORM_IPHONE OR PLATFORM_MAC) + append(DRAPE_TESTABLE_SRC metal/metal_base_context.hpp metal/metal_base_context.mm metal/metal_cleaner.hpp @@ -155,6 +152,15 @@ if (PLATFORM_IPHONE) ) endif() +set(SRC ${DRAPE_TESTABLE_SRC} gl_functions.cpp) + +if (PLATFORM_IPHONE) + append(SRC + hw_texture_ios.hpp + hw_texture_ios.mm + ) +endif() + omim_add_library(${PROJECT_NAME} ${SRC}) # Do not include glm's CMakeLists.txt, because it's outdated and not necessary. @@ -177,6 +183,7 @@ set(DRAPE_LINK_LIBRARIES ICU::i18n expat::expat $<$:-framework\ OpenGL> + $<$:-framework\ Metal> $<$:OpenGL::GL> ) diff --git a/drape/vulkan/vulkan_context_factory.cpp b/drape/vulkan/vulkan_context_factory.cpp new file mode 100644 index 0000000000..d9ec0a3b0c --- /dev/null +++ b/drape/vulkan/vulkan_context_factory.cpp @@ -0,0 +1,387 @@ +#include "drape/vulkan/vulkan_context_factory.hpp" + +#include "drape/drape_diagnostics.hpp" +#include "drape/support_manager.hpp" +#include "drape/vulkan/vulkan_pipeline.hpp" +#include "drape/vulkan/vulkan_utils.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/macros.hpp" +#include "base/src_point.hpp" + +#include +#include + +namespace dp +{ +namespace vulkan +{ +namespace +{ +class DrawVulkanContext : public dp::vulkan::VulkanBaseContext +{ +public: + DrawVulkanContext(VkInstance vulkanInstance, VkPhysicalDevice gpu, + VkPhysicalDeviceProperties const & gpuProperties, VkDevice device, + uint32_t renderingQueueFamilyIndex, + ref_ptr objectManager, uint32_t appVersionCode, + bool hasPartialTextureUpdates) + : dp::vulkan::VulkanBaseContext( + vulkanInstance, gpu, gpuProperties, device, renderingQueueFamilyIndex, objectManager, + make_unique_dp(device, appVersionCode), + hasPartialTextureUpdates) + { + VkQueue queue; + vkGetDeviceQueue(device, renderingQueueFamilyIndex, 0, &queue); + SetRenderingQueue(queue); + CreateCommandPool(); + } + + void MakeCurrent() override + { + m_objectManager->RegisterThread(dp::vulkan::VulkanObjectManager::Frontend); + } +}; + +class UploadVulkanContext : public dp::vulkan::VulkanBaseContext +{ +public: + UploadVulkanContext(VkInstance vulkanInstance, VkPhysicalDevice gpu, + VkPhysicalDeviceProperties const & gpuProperties, VkDevice device, + uint32_t renderingQueueFamilyIndex, + ref_ptr objectManager, + bool hasPartialTextureUpdates) + : dp::vulkan::VulkanBaseContext(vulkanInstance, gpu, gpuProperties, device, + renderingQueueFamilyIndex, objectManager, + nullptr /* pipeline */, hasPartialTextureUpdates) + {} + + void MakeCurrent() override + { + m_objectManager->RegisterThread(dp::vulkan::VulkanObjectManager::Backend); + } + + void Present() override {} + + void Resize(int w, int h) override {} + void SetFramebuffer(ref_ptr framebuffer) override {} + void Init(dp::ApiVersion apiVersion) override + { + CHECK_EQUAL(apiVersion, dp::ApiVersion::Vulkan, ()); + } + + void SetClearColor(dp::Color const & color) override {} + void Clear(uint32_t clearBits, uint32_t storeBits) override {} + void Flush() override {} + void SetDepthTestEnabled(bool enabled) override {} + void SetDepthTestFunction(dp::TestFunction depthFunction) override {} + void SetStencilTestEnabled(bool enabled) override {} + void SetStencilFunction(dp::StencilFace face, + dp::TestFunction stencilFunction) override {} + void SetStencilActions(dp::StencilFace face, + dp::StencilAction stencilFailAction, + dp::StencilAction depthFailAction, + dp::StencilAction passAction) override {} +}; +} // namespace + +VulkanContextFactory::VulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM) +{ + if (InitVulkan() == 0) + { + LOG_ERROR_VK("Could not initialize Vulkan library."); + return; + } + + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pNext = nullptr; + appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.applicationVersion = appVersionCode; + appInfo.engineVersion = appVersionCode; + appInfo.pApplicationName = "OMaps"; + appInfo.pEngineName = "Drape Engine"; + + 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 = m_layers->GetInstanceExtensionsCount(); + instanceCreateInfo.ppEnabledExtensionNames = m_layers->GetInstanceExtensions(); + instanceCreateInfo.enabledLayerCount = m_layers->GetInstanceLayersCount(); + instanceCreateInfo.ppEnabledLayerNames = m_layers->GetInstanceLayers(); +#if defined(OMIM_OS_MAC) + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#endif + + // Enable extra validation features. + VkValidationFeaturesEXT validationFeatures = {}; + const VkValidationFeatureEnableEXT validationFeaturesEnabled[] = { + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT}; + if (m_layers->IsValidationFeaturesEnabled()) + { + validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; + validationFeatures.pNext = nullptr; + validationFeatures.enabledValidationFeatureCount = ARRAY_SIZE(validationFeaturesEnabled), + validationFeatures.pEnabledValidationFeatures = validationFeaturesEnabled; + + instanceCreateInfo.pNext = &validationFeatures; + } + + VkResult statusCode; + statusCode = vkCreateInstance(&instanceCreateInfo, nullptr, &m_vulkanInstance); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkCreateInstance, statusCode); + return; + } + + uint32_t gpuCount = 0; + statusCode = vkEnumeratePhysicalDevices(m_vulkanInstance, &gpuCount, nullptr); + if (statusCode != VK_SUCCESS || gpuCount == 0) + { + LOG_ERROR_VK_CALL(vkEnumeratePhysicalDevices, statusCode); + return; + } + + std::vector tmpGpus(gpuCount); + statusCode = vkEnumeratePhysicalDevices(m_vulkanInstance, &gpuCount, tmpGpus.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkEnumeratePhysicalDevices, statusCode); + return; + } + m_gpu = tmpGpus[0]; + + VkPhysicalDeviceProperties gpuProperties; + vkGetPhysicalDeviceProperties(m_gpu, &gpuProperties); + dp::SupportManager::Version apiVersion{VK_VERSION_MAJOR(gpuProperties.apiVersion), + VK_VERSION_MINOR(gpuProperties.apiVersion), + VK_VERSION_PATCH(gpuProperties.apiVersion)}; + dp::SupportManager::Version driverVersion{VK_VERSION_MAJOR(gpuProperties.driverVersion), + VK_VERSION_MINOR(gpuProperties.driverVersion), + VK_VERSION_PATCH(gpuProperties.driverVersion)}; + if (dp::SupportManager::Instance().IsVulkanForbidden(gpuProperties.deviceName, apiVersion, driverVersion, isCustomROM)) + { + LOG_ERROR_VK("GPU/Driver configuration is not supported."); + return; + } + + uint32_t queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, nullptr); + if (queueFamilyCount == 0) + { + LOG_ERROR_VK("Any queue family wasn't found."); + return; + } + + std::vector queueFamilyProperties(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, + queueFamilyProperties.data()); + + uint32_t renderingQueueFamilyIndex = 0; + for (; renderingQueueFamilyIndex < queueFamilyCount; ++renderingQueueFamilyIndex) + { + if (queueFamilyProperties[renderingQueueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) + break; + } + if (renderingQueueFamilyIndex == queueFamilyCount) + { + LOG_ERROR_VK("Any queue family with VK_QUEUE_GRAPHICS_BIT wasn't found."); + return; + } + + if (!dp::vulkan::VulkanFormatUnpacker::Init(m_gpu)) + return; + + if (!m_layers->Initialize(m_vulkanInstance, m_gpu)) + return; + + float priorities[] = {1.0f}; + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.pNext = nullptr; + queueCreateInfo.flags = 0; + queueCreateInfo.queueCount = 1; + queueCreateInfo.queueFamilyIndex = renderingQueueFamilyIndex; + queueCreateInfo.pQueuePriorities = priorities; + + VkPhysicalDeviceFeatures availableFeatures; + vkGetPhysicalDeviceFeatures(m_gpu, &availableFeatures); + if (!availableFeatures.wideLines) + LOG(LWARNING, ("Widelines Vulkan feature is not supported.")); + + VkDeviceCreateInfo deviceCreateInfo = {}; + VkPhysicalDeviceFeatures enabledFeatures = { + .wideLines = availableFeatures.wideLines, + }; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.pNext = nullptr; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.enabledLayerCount = m_layers->GetDeviceLayersCount(); + deviceCreateInfo.ppEnabledLayerNames = m_layers->GetDeviceLayers(); + deviceCreateInfo.enabledExtensionCount = m_layers->GetDeviceExtensionsCount(); + deviceCreateInfo.ppEnabledExtensionNames = m_layers->GetDeviceExtensions(); + deviceCreateInfo.pEnabledFeatures = nullptr; + if (enableDiagnostics) + { + enabledFeatures.robustBufferAccess = VK_TRUE; + deviceCreateInfo.pEnabledFeatures = &enabledFeatures; + } + + statusCode = vkCreateDevice(m_gpu, &deviceCreateInfo, nullptr, &m_device); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkCreateDevice, statusCode); + return; + } + + INIT_DEBUG_NAME_VK(m_vulkanInstance, m_device); + + VkPhysicalDeviceMemoryProperties memoryProperties; + vkGetPhysicalDeviceMemoryProperties(m_gpu, &memoryProperties); + m_objectManager = make_unique_dp(m_device, gpuProperties.limits, + memoryProperties, + renderingQueueFamilyIndex); + + bool const hasPartialTextureUpdates = + !dp::SupportManager::Instance().IsVulkanTexturePartialUpdateBuggy( + sdkVersion, gpuProperties.deviceName, apiVersion, driverVersion); + + m_drawContext = make_unique_dp( + m_vulkanInstance, m_gpu, gpuProperties, m_device, renderingQueueFamilyIndex, + make_ref(m_objectManager), appVersionCode, hasPartialTextureUpdates); + m_uploadContext = make_unique_dp( + m_vulkanInstance, m_gpu, gpuProperties, m_device, renderingQueueFamilyIndex, + make_ref(m_objectManager), hasPartialTextureUpdates); +} + +VulkanContextFactory::~VulkanContextFactory() +{ + m_drawContext.reset(); + m_uploadContext.reset(); + m_objectManager.reset(); + + if (m_device != nullptr) + { + vkDeviceWaitIdle(m_device); + vkDestroyDevice(m_device, nullptr); + } + + if (m_vulkanInstance != nullptr) + { + m_layers->Uninitialize(m_vulkanInstance); + vkDestroyInstance(m_vulkanInstance, nullptr); + } +} + +bool VulkanContextFactory::IsVulkanSupported() const +{ + return m_vulkanInstance != nullptr && m_gpu != nullptr && m_device != nullptr; +} + +dp::GraphicsContext * VulkanContextFactory::GetDrawContext() +{ + return m_drawContext.get(); +} + +dp::GraphicsContext * VulkanContextFactory::GetResourcesUploadContext() +{ + return m_uploadContext.get(); +} + +bool VulkanContextFactory::IsDrawContextCreated() const +{ + return m_drawContext != nullptr; +} + +bool VulkanContextFactory::IsUploadContextCreated() const +{ + return m_uploadContext != nullptr; +} + +void VulkanContextFactory::SetPresentAvailable(bool available) +{ + if (m_drawContext) + m_drawContext->SetPresentAvailable(available); +} + +bool VulkanContextFactory::QuerySurfaceSize() +{ + auto statusCode = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpu, m_surface, + &m_surfaceCapabilities); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, statusCode); + return false; + } + + uint32_t formatCount = 0; + statusCode = vkGetPhysicalDeviceSurfaceFormatsKHR(m_gpu, m_surface, &formatCount, nullptr); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, statusCode); + return false; + } + + std::vector formats(formatCount); + statusCode = vkGetPhysicalDeviceSurfaceFormatsKHR(m_gpu, m_surface, &formatCount, formats.data()); + if (statusCode != VK_SUCCESS) + { + LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, statusCode); + return false; + } + + uint32_t chosenFormat; + for (chosenFormat = 0; chosenFormat < formatCount; chosenFormat++) + { +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_LINUX) + if (formats[chosenFormat].format == VK_FORMAT_B8G8R8A8_UNORM) + break; +#else + if (formats[chosenFormat].format == VK_FORMAT_R8G8B8A8_UNORM) + break; +#endif + } + if (chosenFormat == formatCount) + { + LOG_ERROR_VK("Any supported surface format wasn't found."); + return false; + } + + if (!(m_surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)) + { + LOG_ERROR_VK("Alpha channel is not supported."); + return false; + } + + m_surfaceFormat = formats[chosenFormat]; + m_surfaceWidth = static_cast(m_surfaceCapabilities.currentExtent.width); + m_surfaceHeight = static_cast(m_surfaceCapabilities.currentExtent.height); + return true; +} + +int VulkanContextFactory::GetWidth() const +{ + return m_surfaceWidth; +} + +int VulkanContextFactory::GetHeight() const +{ + return m_surfaceHeight; +} + +VkInstance VulkanContextFactory::GetVulkanInstance() const +{ + return m_vulkanInstance; +} +} // namespace vulkan +} // namespace dp diff --git a/drape/vulkan/vulkan_context_factory.hpp b/drape/vulkan/vulkan_context_factory.hpp new file mode 100644 index 0000000000..e1582452e0 --- /dev/null +++ b/drape/vulkan/vulkan_context_factory.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "drape/graphics_context_factory.hpp" +#include "drape/vulkan/vulkan_base_context.hpp" +#include "drape/vulkan/vulkan_object_manager.hpp" +#include "drape/vulkan/vulkan_layers.hpp" +#include "drape/pointers.hpp" + +#include + +namespace dp +{ +namespace vulkan +{ +class VulkanContextFactory : public dp::GraphicsContextFactory +{ +public: + VulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM); + ~VulkanContextFactory() override; + + bool IsVulkanSupported() const; + + dp::GraphicsContext * GetDrawContext() override; + dp::GraphicsContext * GetResourcesUploadContext() override; + bool IsDrawContextCreated() const override; + bool IsUploadContextCreated() const override; + void SetPresentAvailable(bool available) override; + + int GetWidth() const; + int GetHeight() const; + + VkInstance GetVulkanInstance() const; + +protected: + bool QuerySurfaceSize(); + + VkInstance m_vulkanInstance = nullptr; + drape_ptr m_layers; + VkPhysicalDevice m_gpu = nullptr; + VkDevice m_device = nullptr; + drape_ptr m_objectManager; + drape_ptr m_drawContext; + drape_ptr m_uploadContext; + + VkSurfaceKHR m_surface = 0; + VkSurfaceFormatKHR m_surfaceFormat; + VkSurfaceCapabilitiesKHR m_surfaceCapabilities; + + int m_surfaceWidth = 0; + int m_surfaceHeight = 0; +}; +} // namespace vulkan +} // namespace dp