// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/vulkan/vulkan_application.h" #include #include #include "flutter/vulkan/vulkan_device.h" #include "flutter/vulkan/vulkan_proc_table.h" #include "flutter/vulkan/vulkan_utilities.h" namespace vulkan { VulkanApplication::VulkanApplication( VulkanProcTable& p_vk, const std::string& application_name, std::vector enabled_extensions, uint32_t application_version, uint32_t api_version) : vk(p_vk), api_version_(api_version), valid_(false) { // Check if we want to enable debugging. std::vector supported_extensions = GetSupportedInstanceExtensions(vk); bool enable_instance_debugging = IsDebuggingEnabled() && ExtensionSupported(supported_extensions, VulkanDebugReport::DebugExtensionName()); // Configure extensions. if (enable_instance_debugging) { enabled_extensions.emplace_back(VulkanDebugReport::DebugExtensionName()); } #if OS_FUCHSIA if (ExtensionSupported(supported_extensions, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { // VK_KHR_get_physical_device_properties2 is a dependency of the memory // capabilities extension, so the validation layers require that it be // enabled. enabled_extensions.emplace_back( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); enabled_extensions.emplace_back( VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); } #endif const char* extensions[enabled_extensions.size()]; for (size_t i = 0; i < enabled_extensions.size(); i++) { extensions[i] = enabled_extensions[i].c_str(); } // Configure layers. const std::vector enabled_layers = InstanceLayersToEnable(vk); const char* layers[enabled_layers.size()]; for (size_t i = 0; i < enabled_layers.size(); i++) { layers[i] = enabled_layers[i].c_str(); } // Configure init structs. const VkApplicationInfo info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, .pApplicationName = application_name.c_str(), .applicationVersion = application_version, .pEngineName = "FlutterEngine", .engineVersion = VK_MAKE_VERSION(1, 0, 0), .apiVersion = api_version_, }; const VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = nullptr, .flags = 0, .pApplicationInfo = &info, .enabledLayerCount = static_cast(enabled_layers.size()), .ppEnabledLayerNames = layers, .enabledExtensionCount = static_cast(enabled_extensions.size()), .ppEnabledExtensionNames = extensions, }; // Perform initialization. VkInstance instance = VK_NULL_HANDLE; if (VK_CALL_LOG_ERROR(vk.CreateInstance(&create_info, nullptr, &instance)) != VK_SUCCESS) { FML_DLOG(INFO) << "Could not create application instance."; return; } // Now that we have an instance, setup instance proc table entries. if (!vk.SetupInstanceProcAddresses(instance)) { FML_DLOG(INFO) << "Could not setup instance proc addresses."; return; } instance_ = {instance, [this](VkInstance i) { FML_LOG(INFO) << "Destroying Vulkan instance"; vk.DestroyInstance(i, nullptr); }}; if (enable_instance_debugging) { auto debug_report = std::make_unique(vk, instance_); if (!debug_report->IsValid()) { FML_LOG(INFO) << "Vulkan debugging was enabled but could not be setup " "for this instance."; } else { debug_report_ = std::move(debug_report); FML_DLOG(INFO) << "Debug reporting is enabled."; } } valid_ = true; } VulkanApplication::~VulkanApplication() = default; bool VulkanApplication::IsValid() const { return valid_; } uint32_t VulkanApplication::GetAPIVersion() const { return api_version_; } const VulkanHandle& VulkanApplication::GetInstance() const { return instance_; } void VulkanApplication::ReleaseInstanceOwnership() { instance_.ReleaseOwnership(); } std::vector VulkanApplication::GetPhysicalDevices() const { if (!IsValid()) { return {}; } uint32_t device_count = 0; if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(instance_, &device_count, nullptr)) != VK_SUCCESS) { FML_DLOG(INFO) << "Could not enumerate physical device."; return {}; } if (device_count == 0) { // No available devices. FML_DLOG(INFO) << "No physical devices found."; return {}; } std::vector physical_devices; physical_devices.resize(device_count); if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices( instance_, &device_count, physical_devices.data())) != VK_SUCCESS) { FML_DLOG(INFO) << "Could not enumerate physical device."; return {}; } return physical_devices; } std::unique_ptr VulkanApplication::AcquireFirstCompatibleLogicalDevice() const { for (auto device_handle : GetPhysicalDevices()) { auto logical_device = std::make_unique(vk, device_handle); if (logical_device->IsValid()) { return logical_device; } } FML_DLOG(INFO) << "Could not acquire compatible logical device."; return nullptr; } std::vector VulkanApplication::GetSupportedInstanceExtensions( const VulkanProcTable& vk) const { if (!vk.EnumerateInstanceExtensionProperties) { return std::vector(); } uint32_t count = 0; if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties( nullptr, &count, nullptr)) != VK_SUCCESS) { return std::vector(); } if (count == 0) { return std::vector(); } std::vector properties; properties.resize(count); if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties( nullptr, &count, properties.data())) != VK_SUCCESS) { return std::vector(); } return properties; } bool VulkanApplication::ExtensionSupported( const std::vector& supported_instance_extensions, std::string extension_name) { uint32_t count = supported_instance_extensions.size(); for (size_t i = 0; i < count; i++) { if (strncmp(supported_instance_extensions[i].extensionName, extension_name.c_str(), extension_name.size()) == 0) { return true; } } return false; } } // namespace vulkan