// Copyright (c) 2018 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 "gpu/vulkan/vulkan_instance.h" #include #include #include "base/logging.h" #include "base/macros.h" #include "gpu/vulkan/vulkan_device_queue.h" #include "gpu/vulkan/vulkan_function_pointers.h" namespace gpu { VKAPI_ATTR VkBool32 VKAPI_CALL VulkanErrorCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) { LOG(ERROR) << pMessage; return VK_TRUE; } VKAPI_ATTR VkBool32 VKAPI_CALL VulkanWarningCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) { LOG(WARNING) << pMessage; return VK_TRUE; } VulkanInstance::VulkanInstance() {} VulkanInstance::~VulkanInstance() { Destroy(); } bool VulkanInstance::Initialize( const std::vector& required_extensions, const std::vector& required_layers) { DCHECK(!vk_instance_); VulkanFunctionPointers* vulkan_function_pointers = gpu::GetVulkanFunctionPointers(); if (!vulkan_function_pointers->BindUnassociatedFunctionPointers()) return false; uint32_t supported_api_version = VK_MAKE_VERSION(1, 0, 0); if (vulkan_function_pointers->vkEnumerateInstanceVersionFn) { vulkan_function_pointers->vkEnumerateInstanceVersionFn( &supported_api_version); } // Use Vulkan 1.1 if it's available. api_version_ = (supported_api_version >= VK_MAKE_VERSION(1, 1, 0)) ? VK_MAKE_VERSION(1, 1, 0) : VK_MAKE_VERSION(1, 0, 0); VkResult result = VK_SUCCESS; VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.pApplicationName = "Chromium"; app_info.apiVersion = api_version_; std::vector enabled_extensions; enabled_extensions.insert(std::end(enabled_extensions), std::begin(required_extensions), std::end(required_extensions)); uint32_t num_instance_exts = 0; result = vkEnumerateInstanceExtensionProperties(nullptr, &num_instance_exts, nullptr); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkEnumerateInstanceExtensionProperties(NULL) failed: " << result; return false; } std::vector instance_exts(num_instance_exts); result = vkEnumerateInstanceExtensionProperties(nullptr, &num_instance_exts, instance_exts.data()); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkEnumerateInstanceExtensionProperties() failed: " << result; return false; } for (const VkExtensionProperties& ext_property : instance_exts) { if (strcmp(ext_property.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { debug_report_enabled_ = true; enabled_extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } } #if DCHECK_IS_ON() for (const char* enabled_extension : enabled_extensions) { bool found = false; for (const VkExtensionProperties& ext_property : instance_exts) { if (strcmp(ext_property.extensionName, enabled_extension) == 0) { found = true; break; } } if (!found) { DLOG(ERROR) << "Required extension " << enabled_extension << " missing from enumerated Vulkan extensions. " "vkCreateInstance will likely fail."; } } #endif std::vector enabled_layer_names; #if DCHECK_IS_ON() uint32_t num_instance_layers = 0; result = vkEnumerateInstanceLayerProperties(&num_instance_layers, nullptr); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkEnumerateInstanceLayerProperties(NULL) failed: " << result; return false; } std::vector instance_layers(num_instance_layers); result = vkEnumerateInstanceLayerProperties(&num_instance_layers, instance_layers.data()); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkEnumerateInstanceLayerProperties() failed: " << result; return false; } std::unordered_set desired_layers({ #if !defined(USE_X11) && !defined(USE_OZONE) // TODO(crbug.com/843346): Make validation work in combination with // VK_KHR_xlib_surface or switch to VK_KHR_xcb_surface. "VK_LAYER_LUNARG_standard_validation", #endif }); for (const VkLayerProperties& layer_property : instance_layers) { if (desired_layers.find(layer_property.layerName) != desired_layers.end()) enabled_layer_names.push_back(layer_property.layerName); } #endif enabled_layer_names.insert(std::end(enabled_layer_names), std::begin(required_layers), std::end(required_layers)); VkInstanceCreateInfo instance_create_info = {}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pApplicationInfo = &app_info; instance_create_info.enabledLayerCount = enabled_layer_names.size(); instance_create_info.ppEnabledLayerNames = enabled_layer_names.data(); instance_create_info.enabledExtensionCount = enabled_extensions.size(); instance_create_info.ppEnabledExtensionNames = enabled_extensions.data(); result = vkCreateInstance(&instance_create_info, nullptr, &vk_instance_); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkCreateInstance() failed: " << result; return false; } enabled_extensions_ = gfx::ExtensionSet(std::begin(enabled_extensions), std::end(enabled_extensions)); #if DCHECK_IS_ON() // Register our error logging function. if (debug_report_enabled_) { PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkCreateDebugReportCallbackEXT")); DCHECK(vkCreateDebugReportCallbackEXT); VkDebugReportCallbackCreateInfoEXT cb_create_info = {}; cb_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; cb_create_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT; cb_create_info.pfnCallback = &VulkanErrorCallback; result = vkCreateDebugReportCallbackEXT(vk_instance_, &cb_create_info, nullptr, &error_callback_); if (VK_SUCCESS != result) { error_callback_ = VK_NULL_HANDLE; DLOG(ERROR) << "vkCreateDebugReportCallbackEXT(ERROR) failed: " << result; return false; } cb_create_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; cb_create_info.pfnCallback = &VulkanWarningCallback; result = vkCreateDebugReportCallbackEXT(vk_instance_, &cb_create_info, nullptr, &warning_callback_); if (VK_SUCCESS != result) { warning_callback_ = VK_NULL_HANDLE; DLOG(ERROR) << "vkCreateDebugReportCallbackEXT(WARN) failed: " << result; return false; } } #endif if (!vulkan_function_pointers->BindInstanceFunctionPointers(vk_instance_)) return false; if (!vulkan_function_pointers->BindPhysicalDeviceFunctionPointers( vk_instance_)) return false; if (gfx::HasExtension(enabled_extensions_, VK_KHR_SURFACE_EXTENSION_NAME)) { vkDestroySurfaceKHR = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkDestroySurfaceKHR")); if (!vkDestroySurfaceKHR) return false; #if defined(USE_X11) vkCreateXlibSurfaceKHR = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkCreateXlibSurfaceKHR")); if (!vkCreateXlibSurfaceKHR) return false; vkGetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast( vkGetInstanceProcAddr( vk_instance_, "vkGetPhysicalDeviceXlibPresentationSupportKHR")); if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) return false; #endif vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR) return false; vkGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkGetPhysicalDeviceSurfaceFormatsKHR")); if (!vkGetPhysicalDeviceSurfaceFormatsKHR) return false; vkGetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkGetPhysicalDeviceSurfaceSupportKHR")); if (!vkGetPhysicalDeviceSurfaceSupportKHR) return false; } return true; } void VulkanInstance::Destroy() { #if DCHECK_IS_ON() if (debug_report_enabled_ && (error_callback_ != VK_NULL_HANDLE || warning_callback_ != VK_NULL_HANDLE)) { PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = reinterpret_cast( vkGetInstanceProcAddr(vk_instance_, "vkDestroyDebugReportCallbackEXT")); DCHECK(vkDestroyDebugReportCallbackEXT); if (error_callback_ != VK_NULL_HANDLE) { vkDestroyDebugReportCallbackEXT(vk_instance_, error_callback_, nullptr); error_callback_ = VK_NULL_HANDLE; } if (warning_callback_ != VK_NULL_HANDLE) { vkDestroyDebugReportCallbackEXT(vk_instance_, warning_callback_, nullptr); warning_callback_ = VK_NULL_HANDLE; } } #endif if (vk_instance_ != VK_NULL_HANDLE) { vkDestroyInstance(vk_instance_, nullptr); vk_instance_ = VK_NULL_HANDLE; } VulkanFunctionPointers* vulkan_function_pointers = gpu::GetVulkanFunctionPointers(); if (vulkan_function_pointers->vulkan_loader_library_) base::UnloadNativeLibrary(vulkan_function_pointers->vulkan_loader_library_); vulkan_function_pointers->vulkan_loader_library_ = nullptr; } } // namespace gpu