From a97523591f203a20d14e0698ae29c509495271fb Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 5 Nov 2021 10:41:35 +0000 Subject: [PATCH] c/util: Add Vulkan helper --- src/xrt/compositor/CMakeLists.txt | 2 + src/xrt/compositor/meson.build | 2 + src/xrt/compositor/util/comp_vulkan.c | 249 ++++++++++++++++++++++++++ src/xrt/compositor/util/comp_vulkan.h | 92 ++++++++++ 4 files changed, 345 insertions(+) create mode 100644 src/xrt/compositor/util/comp_vulkan.c create mode 100644 src/xrt/compositor/util/comp_vulkan.h diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 63bc3e271..2e0656587 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -24,6 +24,8 @@ set(UTIL_SOURCE_FILES util/comp_swapchain.c util/comp_sync.h util/comp_sync.c + util/comp_vulkan.h + util/comp_vulkan.c ) set(RENDER_SOURCE_FILES diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 40e608ff5..5daf16b9e 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -43,6 +43,8 @@ compositor_srcs = [ 'util/comp_swapchain.c', 'util/comp_sync.h', 'util/comp_sync.c', + 'util/comp_vulkan.h', + 'util/comp_vulkan.c', ] compile_args = [] diff --git a/src/xrt/compositor/util/comp_vulkan.c b/src/xrt/compositor/util/comp_vulkan.c new file mode 100644 index 000000000..eb3f8ec8a --- /dev/null +++ b/src/xrt/compositor/util/comp_vulkan.c @@ -0,0 +1,249 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Vulkan code for compositors. + * + * @author Jakob Bornecrantz + * @author Lubosz Sarnecki + * @author Ryan Pavlik + * @ingroup comp_util + */ + +#include "os/os_time.h" + +#include "util/u_handles.h" +#include "util/u_trace_marker.h" + +#include "util/comp_vulkan.h" + + +/* + * + * Helper functions. + * + */ + +#define VK_ERROR_RET(VK, FUNC, MSG, RET) VK_ERROR(VK, FUNC ": %s\n\t" MSG, vk_result_string(RET)) + +static bool +get_device_uuid(struct vk_bundle *vk, int gpu_index, uint8_t *uuid) +{ + VkPhysicalDeviceIDProperties pdidp = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, + }; + + VkPhysicalDeviceProperties2 pdp2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &pdidp, + }; + + VkPhysicalDevice phys[16]; + uint32_t gpu_count = ARRAY_SIZE(phys); + VkResult ret; + + ret = vk->vkEnumeratePhysicalDevices(vk->instance, &gpu_count, phys); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vkEnumeratePhysicalDevices", "Failed to enumerate physical devices.", ret); + return false; + } + + vk->vkGetPhysicalDeviceProperties2(phys[gpu_index], &pdp2); + memcpy(uuid, pdidp.deviceUUID, XRT_GPU_UUID_SIZE); + + return true; +} + +VkResult +fill_in_results(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_args, struct comp_vulkan_results *vk_res) +{ + // Grab the device index from the vk_bundle + vk_res->selected_gpu_index = vk->physical_device_index; + + // Store physical device UUID for compositor in settings + if (vk_res->selected_gpu_index >= 0) { + if (get_device_uuid(vk, vk_res->selected_gpu_index, vk_res->selected_gpu_deviceUUID)) { + char uuid_str[XRT_GPU_UUID_SIZE * 3 + 1] = {0}; + for (int i = 0; i < XRT_GPU_UUID_SIZE; i++) { + sprintf(uuid_str + i * 3, "%02x ", vk_res->selected_gpu_deviceUUID[i]); + } + VK_DEBUG(vk, "Selected %d with uuid: %s", vk_res->selected_gpu_index, uuid_str); + } else { + VK_ERROR(vk, "Failed to get device %d uuid", vk_res->selected_gpu_index); + } + } + + // By default suggest GPU used by compositor to clients + if (vk_res->client_gpu_index < 0) { + vk_res->client_gpu_index = vk_res->selected_gpu_index; + } + + // Store physical device UUID suggested to clients in settings + if (vk_res->client_gpu_index >= 0) { + if (get_device_uuid(vk, vk_res->client_gpu_index, vk_res->client_gpu_deviceUUID)) { + char uuid_str[XRT_GPU_UUID_SIZE * 3 + 1] = {0}; + for (int i = 0; i < XRT_GPU_UUID_SIZE; i++) { + sprintf(uuid_str + i * 3, "%02x ", vk_res->client_gpu_deviceUUID[i]); + } + // Trailing space above, means 'to' should be right next to '%s'. + VK_DEBUG(vk, "Suggest %d with uuid: %sto clients", vk_res->client_gpu_index, uuid_str); + } else { + VK_ERROR(vk, "Failed to get device %d uuid", vk_res->client_gpu_index); + } + } + + return VK_SUCCESS; +} + + +/* + * + * Creation functions. + * + */ + +static VkResult +create_instance(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_args) +{ + VkResult ret; + + VkApplicationInfo app_info = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "Monado Compositor", + .pEngineName = "Monado", + .apiVersion = VK_MAKE_VERSION(1, 0, 2), + }; + + VkInstanceCreateInfo instance_info = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &app_info, + .enabledExtensionCount = vk_args->instance_extensions.num, + .ppEnabledExtensionNames = vk_args->instance_extensions.array, + }; + + ret = vk->vkCreateInstance(&instance_info, NULL, &vk->instance); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vkCreateInstance", "Failed to create Vulkan instance", ret); + return ret; + } + + ret = vk_get_instance_functions(vk); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vk_get_instance_functions", "Failed to get Vulkan instance functions.", ret); + return ret; + } + + return ret; +} + +static VkResult +create_device(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_args) +{ + VkResult ret; + + const char *prio_strs[3] = { + "realtime", + "high", + "normal", + }; + + VkQueueGlobalPriorityEXT prios[3] = { + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT, // This is the one we really want. + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT, // Probably not as good but something. + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT, // Default fallback. + }; + + const bool only_compute_queue = vk_args->only_compute_queue; + + struct vk_device_features device_features = { + .shader_storage_image_write_without_format = true, + .null_descriptor = only_compute_queue, + }; + + // No other way then to try to see if realtime is available. + for (size_t i = 0; i < ARRAY_SIZE(prios); i++) { + ret = vk_create_device( // + vk, // + vk_args->selected_gpu_index, // + only_compute_queue, // compute_only + prios[i], // global_priority + vk_args->required_device_extensions.array, // + vk_args->required_device_extensions.num, // + vk_args->optional_device_extensions.array, // + vk_args->optional_device_extensions.num, // + &device_features); // optional_device_features + + // All ok! + if (ret == VK_SUCCESS) { + VK_INFO(vk, "Created device and %s queue with %s priority.", + only_compute_queue ? "compute" : "graphics", prio_strs[i]); + break; + } + + // Try a lower priority. + if (ret == VK_ERROR_NOT_PERMITTED_EXT) { + continue; + } + + // Some other error! + VK_ERROR_RET(vk, "vk_create_device", "Failed to create Vulkan device.", ret); + return ret; + } + + ret = vk_init_mutex(vk); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vk_init_mutex", "Failed to init mutex.", ret); + return ret; + } + + ret = vk_init_cmd_pool(vk); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vk_init_cmd_pool", "Failed to init command pool.", ret); + return ret; + } + + return VK_SUCCESS; +} + + +/* + * + * 'Exported' function. + * + */ + +bool +comp_vulkan_init_bundle(struct vk_bundle *vk, + const struct comp_vulkan_arguments *vk_args, + struct comp_vulkan_results *vk_res) +{ + VkResult ret; + + vk->ll = vk_args->log_level; + + ret = vk_get_loader_functions(vk, vk_args->get_instance_proc_address); + if (ret != VK_SUCCESS) { + VK_ERROR_RET(vk, "vk_get_loader_functions", "Failed to get VkInstance get process address.", ret); + return false; + } + + ret = create_instance(vk, vk_args); + if (ret != VK_SUCCESS) { + // Error already reported. + return false; + } + + ret = create_device(vk, vk_args); + if (ret != VK_SUCCESS) { + // Error already reported. + return false; + } + + ret = fill_in_results(vk, vk_args, vk_res); + if (ret != VK_SUCCESS) { + // Error already reported. + return false; + } + + return true; +} diff --git a/src/xrt/compositor/util/comp_vulkan.h b/src/xrt/compositor/util/comp_vulkan.h new file mode 100644 index 000000000..6dc61e00e --- /dev/null +++ b/src/xrt/compositor/util/comp_vulkan.h @@ -0,0 +1,92 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Vulkan code for compositors. + * @author Jakob Bornecrantz + * @ingroup comp_util + */ + +#pragma once + +#include "xrt/xrt_compositor.h" +#include "util/u_logging.h" +#include "vk/vk_helpers.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * Simple helper struct for lists of arrays. + */ +struct comp_vulkan_extension_list +{ + const char **array; + uint32_t num; +}; + +/*! + * Arguments to Vulkan bundle initialisation, all args needs setting. + */ +struct comp_vulkan_arguments +{ + //! Function to get all Vulkan functions from. + PFN_vkGetInstanceProcAddr get_instance_proc_address; + + //! Extensions that the instance is created with. + struct comp_vulkan_extension_list instance_extensions; + + //! Extensions that the instance is created with. + struct comp_vulkan_extension_list required_device_extensions; + + //! Extensions that the instance is created with. + struct comp_vulkan_extension_list optional_device_extensions; + + //! Logging level to be set on the @ref vk_bundle. + enum u_logging_level log_level; + + //! Should we look for a queue with no graphics, only compute. + bool only_compute_queue; + + //! Vulkan physical device to be selected, -1 for auto. + int selected_gpu_index; + + //! Vulkan physical device index for clients to use, -1 for auto. + int client_gpu_index; +}; + +/*! + * Extra results from Vulkan bundle initialisation. + */ +struct comp_vulkan_results +{ + //! Vulkan physical device selected. + int selected_gpu_index; + + //! Vulkan physical device index for clients to use. + int client_gpu_index; + + //! Selected Vulkan device UUID. + uint8_t selected_gpu_deviceUUID[XRT_GPU_UUID_SIZE]; + + //! Selected Vulkan device UUID to suggest to clients. + uint8_t client_gpu_deviceUUID[XRT_GPU_UUID_SIZE]; +}; + +/*! + * Fully initialises a @ref vk_bundle, by creating instance, device and queue. + * + * @ingroup comp_util + */ +bool +comp_vulkan_init_bundle(struct vk_bundle *vk, + const struct comp_vulkan_arguments *vk_args, + struct comp_vulkan_results *vk_res); + + +#ifdef __cplusplus +} +#endif