diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 699fd14d3e146..52b39fc9bd860 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -14,11 +14,7 @@ namespace impeller { static constexpr const char* kInstanceLayer = "ImpellerInstance"; -CapabilitiesVK::CapabilitiesVK(bool enable_validations) - : enable_validations_(enable_validations) { - if (enable_validations_) { - FML_LOG(INFO) << "Vulkan validations are enabled."; - } +CapabilitiesVK::CapabilitiesVK(bool enable_validations) { auto extensions = vk::enumerateInstanceExtensionProperties(); auto layers = vk::enumerateInstanceLayerProperties(); @@ -42,6 +38,17 @@ CapabilitiesVK::CapabilitiesVK(bool enable_validations) } } + validations_enabled_ = + enable_validations && HasLayer("VK_LAYER_KHRONOS_validation"); + if (enable_validations && !validations_enabled_) { + FML_LOG(ERROR) + << "Requested Impeller context creation with validations but the " + "validation layers could not be found. Expect no Vulkan validation " + "checks!"; + } + if (validations_enabled_) { + FML_LOG(INFO) << "Vulkan validations are enabled."; + } is_valid_ = true; } @@ -52,19 +59,15 @@ bool CapabilitiesVK::IsValid() const { } bool CapabilitiesVK::AreValidationsEnabled() const { - return enable_validations_; + return validations_enabled_; } std::optional> CapabilitiesVK::GetEnabledLayers() const { std::vector required; - if (enable_validations_) { - if (!HasLayer("VK_LAYER_KHRONOS_validation")) { - VALIDATION_LOG - << "Requested validations but the validation layer was not found."; - return std::nullopt; - } + if (validations_enabled_) { + // The presence of this layer is already checked in the ctor. required.push_back("VK_LAYER_KHRONOS_validation"); } @@ -131,7 +134,7 @@ CapabilitiesVK::GetEnabledInstanceExtensions() const { return std::nullopt; } - if (enable_validations_) { + if (validations_enabled_) { if (!HasExtension("VK_EXT_debug_utils")) { VALIDATION_LOG << "Requested validations but could not find the " "VK_EXT_debug_utils extension."; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 2e5db50c01cb3..34e763927d8db 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -100,7 +100,7 @@ class CapabilitiesVK final : public Capabilities, PixelFormat GetDefaultDepthStencilFormat() const override; private: - const bool enable_validations_; + bool validations_enabled_ = false; std::map> exts_; std::set optional_device_extensions_; mutable PixelFormat default_color_format_ = PixelFormat::kUnknown; diff --git a/impeller/renderer/backend/vulkan/context_vk_unittests.cc b/impeller/renderer/backend/vulkan/context_vk_unittests.cc index f584f104689ee..a7f4965a97e8e 100644 --- a/impeller/renderer/backend/vulkan/context_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/context_vk_unittests.cc @@ -83,5 +83,13 @@ TEST(ContextVKTest, DeletePipelineLibraryAfterContext) { "vkDestroyDevice") != functions->end()); } +TEST(ContextVKTest, CanCreateContextInAbsenceOfValidationLayers) { + // The mocked methods don't report the presence of a validation layer but we + // explicitly ask for validation. Context creation should continue anyway. + auto context = CreateMockVulkanContext( + [](auto& settings) { settings.enable_validation = true; }); + ASSERT_NE(context, nullptr); +} + } // namespace testing } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/test/mock_vulkan.cc b/impeller/renderer/backend/vulkan/test/mock_vulkan.cc index c2ee56e309ff2..387193ae04461 100644 --- a/impeller/renderer/backend/vulkan/test/mock_vulkan.cc +++ b/impeller/renderer/backend/vulkan/test/mock_vulkan.cc @@ -490,10 +490,14 @@ PFN_vkVoidFunction GetMockVulkanProcAddress(VkInstance instance, } // namespace -std::shared_ptr CreateMockVulkanContext(void) { - ContextVK::Settings settings; +std::shared_ptr CreateMockVulkanContext( + const std::function& settings_callback) { auto message_loop = fml::ConcurrentMessageLoop::Create(); + ContextVK::Settings settings; settings.proc_address_callback = GetMockVulkanProcAddress; + if (settings_callback) { + settings_callback(settings); + } return ContextVK::Create(std::move(settings)); } diff --git a/impeller/renderer/backend/vulkan/test/mock_vulkan.h b/impeller/renderer/backend/vulkan/test/mock_vulkan.h index 280b47e981da8..2984db473ff09 100644 --- a/impeller/renderer/backend/vulkan/test/mock_vulkan.h +++ b/impeller/renderer/backend/vulkan/test/mock_vulkan.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -15,7 +16,18 @@ namespace testing { std::shared_ptr> GetMockVulkanFunctions( VkDevice device); -std::shared_ptr CreateMockVulkanContext(void); +//------------------------------------------------------------------------------ +/// @brief Create a Vulkan context with Vulkan functions mocked. The caller +/// is given a chance to tinker on the settings right before a +/// context is created. +/// +/// @param[in] settings_callback The settings callback +/// +/// @return A context if one can be created. +/// +std::shared_ptr CreateMockVulkanContext( + const std::function& settings_callback = + nullptr); } // namespace testing } // namespace impeller diff --git a/shell/platform/android/android_context_vulkan_impeller.cc b/shell/platform/android/android_context_vulkan_impeller.cc index 7c5743ea48b2b..d9521c35b2b89 100644 --- a/shell/platform/android/android_context_vulkan_impeller.cc +++ b/shell/platform/android/android_context_vulkan_impeller.cc @@ -38,14 +38,17 @@ static std::shared_ptr CreateImpellerContext( settings.cache_directory = fml::paths::GetCachesDirectory(); settings.enable_validation = enable_vulkan_validation; - if (settings.enable_validation) { + auto context = impeller::ContextVK::Create(std::move(settings)); + + if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities()) + .AreValidationsEnabled()) { FML_LOG(ERROR) << "Using the Impeller rendering backend (Vulkan with " "Validation Layers)."; } else { FML_LOG(ERROR) << "Using the Impeller rendering backend (Vulkan)."; } - return impeller::ContextVK::Create(std::move(settings)); + return context; } AndroidContextVulkanImpeller::AndroidContextVulkanImpeller(