[Impeller] If validations are enabled but not found, still create the VK context. (flutter/engine#45674)

Fixes https://github.com/flutter/flutter/issues/131714
This commit is contained in:
Chinmay Garde 2023-09-12 14:30:04 -07:00 committed by GitHub
parent f49eb6e0aa
commit cf31c43c78
6 changed files with 49 additions and 19 deletions

View File

@ -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<std::vector<std::string>> CapabilitiesVK::GetEnabledLayers()
const {
std::vector<std::string> 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.";

View File

@ -100,7 +100,7 @@ class CapabilitiesVK final : public Capabilities,
PixelFormat GetDefaultDepthStencilFormat() const override;
private:
const bool enable_validations_;
bool validations_enabled_ = false;
std::map<std::string, std::set<std::string>> exts_;
std::set<OptionalDeviceExtensionVK> optional_device_extensions_;
mutable PixelFormat default_color_format_ = PixelFormat::kUnknown;

View File

@ -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

View File

@ -513,10 +513,14 @@ PFN_vkVoidFunction GetMockVulkanProcAddress(VkInstance instance,
} // namespace
std::shared_ptr<ContextVK> CreateMockVulkanContext(void) {
ContextVK::Settings settings;
std::shared_ptr<ContextVK> CreateMockVulkanContext(
const std::function<void(ContextVK::Settings&)>& 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));
}

View File

@ -4,6 +4,7 @@
#pragma once
#include <functional>
#include <string>
#include <vector>
@ -15,7 +16,18 @@ namespace testing {
std::shared_ptr<std::vector<std::string>> GetMockVulkanFunctions(
VkDevice device);
std::shared_ptr<ContextVK> 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<ContextVK> CreateMockVulkanContext(
const std::function<void(ContextVK::Settings&)>& settings_callback =
nullptr);
} // namespace testing
} // namespace impeller

View File

@ -38,14 +38,17 @@ static std::shared_ptr<impeller::Context> 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(