From b89775a79093d302a336b3876939a3c6b9ff3514 Mon Sep 17 00:00:00 2001 From: Roman Kuznetsov Date: Fri, 3 May 2019 10:58:29 +0300 Subject: [PATCH] [vulkan] Forbid Vulkan for not standard compliant Adreno drivers --- android/jni/com/mapswithme/maps/Framework.cpp | 12 +++++-- drape/support_manager.cpp | 35 ++++++++++++++----- drape/support_manager.hpp | 7 ++++ drape/vulkan/vulkan_pipeline.cpp | 18 ++++++++-- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index c5bf8ec19a..5a773d66a6 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -19,11 +19,13 @@ #include "storage/storage_helpers.hpp" -#include "drape/pointers.hpp" -#include "drape/visual_scale.hpp" #include "drape_frontend/user_event_stream.hpp" #include "drape_frontend/visual_params.hpp" +#include "drape/pointers.hpp" +#include "drape/support_manager.hpp" +#include "drape/visual_scale.hpp" + #include "coding/file_container.hpp" #include "coding/file_name_utils.hpp" @@ -173,7 +175,11 @@ bool Framework::DestroySurfaceOnDetach() bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi, bool firstLaunch, bool launchByDeepLink, int appVersionCode) { - if (m_work.LoadPreferredGraphicsAPI() == dp::ApiVersion::Vulkan) + auto const vulkanForbidden = dp::SupportManager::Instance().IsVulkanForbidden(); + if (vulkanForbidden) + LOG(LWARNING, ("Vulkan API is forbidden on this device.")); + + if (m_work.LoadPreferredGraphicsAPI() == dp::ApiVersion::Vulkan && !vulkanForbidden) { m_vulkanContextFactory = make_unique_dp(appVersionCode); if (!CastFactory(m_vulkanContextFactory)->IsVulkanSupported()) diff --git a/drape/support_manager.cpp b/drape/support_manager.cpp index 3e8ab410c0..b9d0519acf 100644 --- a/drape/support_manager.cpp +++ b/drape/support_manager.cpp @@ -17,6 +17,7 @@ namespace dp { char const * kSupportedAntialiasing = "Antialiasing"; +char const * kVulkanForbidden = "VulkanForbidden"; void SupportManager::Init(ref_ptr context) { @@ -24,22 +25,23 @@ void SupportManager::Init(ref_ptr context) if (m_isInitialized) return; - std::string const renderer = context->GetRendererName(); - std::string const version = context->GetRendererVersion(); - LOG(LINFO, ("Renderer =", renderer, "| Api =", context->GetApiVersion(), "| Version =", version)); + m_rendererName = context->GetRendererName(); + m_rendererVersion = context->GetRendererVersion(); + LOG(LINFO, ("Renderer =", m_rendererName, "| Api =", context->GetApiVersion(), "| Version =", m_rendererVersion)); - alohalytics::Stats::Instance().LogEvent("GPU", renderer); + alohalytics::Stats::Instance().LogEvent("GPU", m_rendererName); - m_isSamsungGoogleNexus = (renderer == "PowerVR SGX 540" && version.find("GOOGLENEXUS.ED945322") != string::npos); + m_isSamsungGoogleNexus = (m_rendererName == "PowerVR SGX 540" && + m_rendererVersion.find("GOOGLENEXUS.ED945322") != string::npos); if (m_isSamsungGoogleNexus) LOG(LINFO, ("Samsung Google Nexus detected.")); - if (renderer.find("Adreno") != std::string::npos) + if (m_rendererName.find("Adreno") != std::string::npos) { std::vector const models = { "200", "203", "205", "220", "225" }; for (auto const & model : models) { - if (renderer.find(model) != std::string::npos) + if (m_rendererName.find(model) != std::string::npos) { LOG(LINFO, ("Adreno 200 device detected.")); m_isAdreno200 = true; @@ -48,7 +50,7 @@ void SupportManager::Init(ref_ptr context) } } - m_isTegra = (renderer.find("Tegra") != std::string::npos); + m_isTegra = (m_rendererName.find("Tegra") != std::string::npos); if (m_isTegra) LOG(LINFO, ("NVidia Tegra device detected.")); @@ -82,7 +84,7 @@ void SupportManager::Init(ref_ptr context) // std::vector const models = {"Mali-G71", "Mali-T880", "Adreno (TM) 540", // "Adreno (TM) 530", "Adreno (TM) 430"}; // m_isAntialiasingEnabledByDefault = -// (std::find(models.begin(), models.end(), renderer) != models.end()); +// (std::find(models.begin(), models.end(), m_rendererName) != models.end()); //#else // m_isAntialiasingEnabledByDefault = true; //#endif @@ -92,6 +94,21 @@ void SupportManager::Init(ref_ptr context) m_isInitialized = true; } +void SupportManager::ForbidVulkan() +{ + alohalytics::Stats::Instance().LogEvent("VulkanForbidden", {{"GPU", m_rendererName}, + {"Driver", m_rendererVersion}}); + settings::Set(kVulkanForbidden, true); +} + +bool SupportManager::IsVulkanForbidden() const +{ + bool forbidden; + if (!settings::Get(kVulkanForbidden, forbidden)) + forbidden = false; + return forbidden; +} + SupportManager & SupportManager::Instance() { static SupportManager manager; diff --git a/drape/support_manager.hpp b/drape/support_manager.hpp index f12a997880..fb7b778afc 100644 --- a/drape/support_manager.hpp +++ b/drape/support_manager.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace dp { @@ -32,9 +33,15 @@ public: float GetMaxLineWidth() const { return m_maxLineWidth; } uint32_t GetMaxTextureSize() const { return m_maxTextureSize; } + // These functions can be used without manager initialization. + void ForbidVulkan(); + bool IsVulkanForbidden() const; + private: SupportManager() = default; + std::string m_rendererName; + std::string m_rendererVersion; bool m_isSamsungGoogleNexus = false; bool m_isAdreno200 = false; bool m_isTegra = false; diff --git a/drape/vulkan/vulkan_pipeline.cpp b/drape/vulkan/vulkan_pipeline.cpp index 742ca59c4c..b6ae398282 100644 --- a/drape/vulkan/vulkan_pipeline.cpp +++ b/drape/vulkan/vulkan_pipeline.cpp @@ -1,6 +1,8 @@ #include "drape/vulkan/vulkan_pipeline.hpp" #include "drape/vulkan/vulkan_utils.hpp" +#include "drape/support_manager.hpp" + #include "platform/platform.hpp" #include "coding/file_name_utils.hpp" @@ -424,8 +426,20 @@ VkPipeline VulkanPipeline::GetPipeline(VkDevice device, PipelineKey const & key) pipelineCreateInfo.pStages = shaders.data(); VkPipeline pipeline; - CHECK_VK_CALL(vkCreateGraphicsPipelines(device, m_vulkanPipelineCache, 1, &pipelineCreateInfo, - nullptr, &pipeline)); + auto const result = vkCreateGraphicsPipelines(device, m_vulkanPipelineCache, 1, + &pipelineCreateInfo, nullptr, &pipeline); + if (result == VK_INCOMPLETE) + { + // Some Adreno GPUs return this not standard compliant code. + // https://developer.qualcomm.com/forum/qdn-forums/software/adreno-gpu-sdk/34709 + // Now we are not able to continue using Vulkan rendering on them. + dp::SupportManager::Instance().ForbidVulkan(); + CHECK(false, ("Fatal driver issue.")); + } + else + { + CHECK_RESULT_VK_CALL(vkCreateGraphicsPipelines, result); + } m_pipelineCache.insert(std::make_pair(key, pipeline)); m_isChanged = true;