| // Copyright 2018 The clvk authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <string> |
| #include <vector> |
| |
| #include <vulkan/vulkan.h> |
| |
| #include "config.hpp" |
| #include "device.hpp" |
| #include "init.hpp" |
| #include "log.hpp" |
| #include "memory.hpp" |
| #include "objects.hpp" |
| #include "queue.hpp" |
| #include "tracing.hpp" |
| |
| static VkBool32 VKAPI_PTR debugCallback( |
| VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, |
| uint64_t object, size_t location, int32_t messageCode, |
| const char* pLayerPrefix, const char* pMessage, void* pUserData) { |
| UNUSED(objectType); |
| UNUSED(object); |
| UNUSED(location); |
| UNUSED(messageCode); |
| UNUSED(pLayerPrefix); |
| UNUSED(pUserData); |
| |
| if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { |
| cvk_error_group(loggroup::validation, "%s", pMessage); |
| } else if ((flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) || |
| (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) { |
| cvk_warn_group(loggroup::validation, "%s", pMessage); |
| } else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { |
| cvk_info_group(loggroup::validation, "%s", pMessage); |
| } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { |
| cvk_debug_group(loggroup::validation, "%s", pMessage); |
| } else { |
| cvk_error_group(loggroup::validation, "%s", pMessage); |
| } |
| |
| return VK_FALSE; |
| } |
| |
| void clvk_global_state::init_vulkan() { |
| VkResult res; |
| |
| // Handle validation layers config |
| const char* validation_layers[] = { |
| "VK_LAYER_KHRONOS_validation", |
| "VK_LAYER_LUNARG_standard_validation", |
| }; |
| |
| if (config.validation_layers) { |
| cvk_info("Enabling validation layers."); |
| } |
| |
| // Discover, log and select layers |
| uint32_t numLayerProperties; |
| res = vkEnumerateInstanceLayerProperties(&numLayerProperties, nullptr); |
| CVK_VK_CHECK_FATAL(res, "Could not query layers"); |
| cvk_info("%u layers visible", numLayerProperties); |
| |
| std::vector<VkLayerProperties> layerProperties(numLayerProperties); |
| res = vkEnumerateInstanceLayerProperties(&numLayerProperties, |
| layerProperties.data()); |
| CVK_VK_CHECK_FATAL(res, "Could not query layers"); |
| |
| std::vector<const char*> enabledLayers; |
| bool validation_layers_found = false; |
| for (uint32_t i = 0; i < numLayerProperties; i++) { |
| cvk_info(" %s, spec version %s, impl version %u", |
| layerProperties[i].layerName, |
| vulkan_version_string(layerProperties[i].specVersion).c_str(), |
| layerProperties[i].implementationVersion); |
| if (config.validation_layers) { |
| for (auto dl : validation_layers) { |
| if (!strcmp(layerProperties[i].layerName, dl)) { |
| cvk_info(" ENABLING"); |
| enabledLayers.push_back(dl); |
| validation_layers_found = true; |
| } |
| } |
| } |
| } |
| |
| if (config.validation_layers && !validation_layers_found) { |
| cvk_warn("Validation layers are enabled but none have been found"); |
| } |
| |
| // Print extension info |
| uint32_t numExtensionProperties; |
| res = vkEnumerateInstanceExtensionProperties( |
| nullptr, &numExtensionProperties, nullptr); |
| CVK_VK_CHECK_FATAL(res, "Could not query extensions"); |
| cvk_info("%u extensions are supported", numExtensionProperties); |
| |
| std::vector<VkExtensionProperties> extensionProperties( |
| numExtensionProperties); |
| res = vkEnumerateInstanceExtensionProperties( |
| nullptr, &numExtensionProperties, extensionProperties.data()); |
| CVK_VK_CHECK_FATAL(res, "Could not query extensions"); |
| |
| std::vector<const char*> enabledExtensions; |
| |
| const std::vector<const char*> desired_extensions = { |
| VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, |
| VK_EXT_DEBUG_REPORT_EXTENSION_NAME, |
| VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, |
| }; |
| |
| for (size_t i = 0; i < numExtensionProperties; i++) { |
| cvk_info(" %s, spec version %u", extensionProperties[i].extensionName, |
| extensionProperties[i].specVersion); |
| |
| for (auto name : desired_extensions) { |
| if (!strcmp(name, extensionProperties[i].extensionName)) { |
| enabledExtensions.push_back(name); |
| cvk_info(" ENABLING"); |
| break; |
| } |
| } |
| } |
| |
| m_debug_report_enabled = |
| std::find(enabledExtensions.begin(), enabledExtensions.end(), |
| VK_EXT_DEBUG_REPORT_EXTENSION_NAME) != |
| enabledExtensions.end(); |
| |
| // Create the instance |
| VkApplicationInfo appInfo = { |
| VK_STRUCTURE_TYPE_APPLICATION_INFO, |
| nullptr, |
| "clvk", |
| 0, // TODO applicationVersion |
| "clvk", |
| 0, // TODO engineVersion |
| VK_MAKE_VERSION(1, 3, 0) |
| }; |
| |
| VkInstanceCreateInfo info = { |
| VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType |
| nullptr, // pNext |
| 0, // flags |
| &appInfo, // pApplicationInfo |
| static_cast<uint32_t>(enabledLayers.size()), // enabledLayerCount |
| enabledLayers.data(), // ppEnabledLayerNames |
| static_cast<uint32_t>( |
| enabledExtensions.size()), // enabledExtensionCount |
| enabledExtensions.data(), // ppEnabledExtensionNames |
| }; |
| |
| res = vkCreateInstance(&info, nullptr, &m_vulkan_instance); |
| CVK_VK_CHECK_FATAL(res, "Could not create the instance"); |
| cvk_info("Created the VkInstance"); |
| |
| // Create debug callback |
| VkDebugReportCallbackCreateInfoEXT callbackInfo = { |
| VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, // sType |
| NULL, // pNext |
| VK_DEBUG_REPORT_ERROR_BIT_EXT | // flags |
| VK_DEBUG_REPORT_DEBUG_BIT_EXT | |
| VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | |
| VK_DEBUG_REPORT_INFORMATION_BIT_EXT | |
| VK_DEBUG_REPORT_WARNING_BIT_EXT, |
| &debugCallback, // pfnCallback |
| NULL // pUserData |
| }; |
| |
| if (m_debug_report_enabled) { |
| auto func = |
| CVK_VK_GET_INSTANCE_PROC(this, vkCreateDebugReportCallbackEXT); |
| |
| res = func(m_vulkan_instance, &callbackInfo, nullptr, |
| &m_vulkan_debug_callback); |
| CVK_VK_CHECK_FATAL(res, "Can't setup debug callback"); |
| } else { |
| cvk_warn("VK_EXT_debug_report not enabled"); |
| } |
| } |
| |
| void clvk_global_state::term_vulkan() { |
| if (m_debug_report_enabled) { |
| auto func = |
| CVK_VK_GET_INSTANCE_PROC(this, vkDestroyDebugReportCallbackEXT); |
| func(m_vulkan_instance, m_vulkan_debug_callback, nullptr); |
| } |
| vkDestroyInstance(m_vulkan_instance, nullptr); |
| } |
| |
| void clvk_global_state::init_platform() { |
| |
| m_platform = new cvk_platform(); |
| |
| uint32_t numDevices; |
| VkResult res = |
| vkEnumeratePhysicalDevices(m_vulkan_instance, &numDevices, nullptr); |
| CVK_VK_CHECK_FATAL(res, "Could not enumerate physical devices"); |
| cvk_info("Found %u physical devices", numDevices); |
| |
| std::vector<VkPhysicalDevice> physicalDevices(numDevices); |
| res = vkEnumeratePhysicalDevices(m_vulkan_instance, &numDevices, |
| physicalDevices.data()); |
| CVK_VK_CHECK_FATAL(res, "Could not enumerate physical devices"); |
| |
| for (uint32_t i = 0; i < numDevices; ++i) { |
| if (!m_platform->create_device(m_vulkan_instance, physicalDevices[i])) { |
| cvk_error("Could not create CL device from Vulkan device!"); |
| } |
| } |
| |
| auto num_devices = m_platform->devices().size(); |
| if (num_devices == 0) { |
| cvk_fatal("Could not initialise any device!"); |
| } else { |
| cvk_info("Initialised %zu devices", num_devices); |
| } |
| } |
| |
| void clvk_global_state::term_platform() { delete m_platform; } |
| |
| void clvk_global_state::init_executors() { |
| m_thread_pool = new cvk_executor_thread_pool(); |
| } |
| |
| void clvk_global_state::term_executors() { delete m_thread_pool; } |
| |
| clvk_global_state::clvk_global_state() { |
| init_early_config(); |
| init_logging(); |
| init_config(); |
| cvk_info("Starting initialisation"); |
| init_tracing(); |
| init_vulkan(); |
| init_platform(); |
| init_executors(); |
| cvk_info("Initialisation complete"); |
| } |
| |
| clvk_global_state::~clvk_global_state() { |
| if (config.destroy_global_state) { |
| term_executors(); |
| term_platform(); |
| term_vulkan(); |
| term_tracing(); |
| term_logging(); |
| } |
| } |
| |
| static clvk_global_state* gGlobalState; |
| static std::once_flag gInitOnceFlag; |
| |
| static void destroy_global_state() { delete gGlobalState; } |
| |
| static void init_global_state() { |
| gGlobalState = new clvk_global_state(); |
| #ifndef WIN32 |
| if (atexit(destroy_global_state) != 0) { |
| cvk_fatal( |
| "Could not register global state destructor using atexit()\n"); |
| } |
| #endif |
| } |
| |
| clvk_global_state* get_or_init_global_state() { |
| std::call_once(gInitOnceFlag, init_global_state); |
| return gGlobalState; |
| } |