blob: 90d1ce7c9da17173f19f808a1bd4965df6576e33 [file] [edit]
// 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;
}