From 7b4b9ee7ee082152d42342c63e76c3a0b01ceeb6 Mon Sep 17 00:00:00 2001 From: Konstantin Seurer Date: Tue, 26 Jul 2022 16:46:49 +0200 Subject: [PATCH] vulkan: Add common physical device management Add common entrypoints for enumerating physical devices, based on the RADV implementation. Signed-off-by: Konstantin Seurer Reviewed-by: Jason Ekstrand Reviewed-by: Samuel Pitoiset Part-of: --- src/vulkan/runtime/vk_instance.c | 142 ++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_instance.h | 43 ++++++++++ src/vulkan/runtime/vk_physical_device.h | 5 ++ 3 files changed, 190 insertions(+) diff --git a/src/vulkan/runtime/vk_instance.c b/src/vulkan/runtime/vk_instance.c index 66b896f..21a0067 100644 --- a/src/vulkan/runtime/vk_instance.c +++ b/src/vulkan/runtime/vk_instance.c @@ -23,12 +23,17 @@ #include "vk_instance.h" +#ifdef HAVE_LIBDRM +#include +#endif + #include "vk_alloc.h" #include "vk_common_entrypoints.h" #include "vk_dispatch_trampolines.h" #include "vk_log.h" #include "vk_util.h" #include "vk_debug_utils.h" +#include "vk_physical_device.h" #include "compiler/glsl_types.h" @@ -176,14 +181,34 @@ vk_instance_init(struct vk_instance *instance, list_inithead(&instance->debug_utils.callbacks); + list_inithead(&instance->physical_devices.list); + + if (mtx_init(&instance->physical_devices.mutex, mtx_plain) != 0) { + mtx_destroy(&instance->debug_report.callbacks_mutex); + mtx_destroy(&instance->debug_utils.callbacks_mutex); + return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); + } + glsl_type_singleton_init_or_ref(); return VK_SUCCESS; } +static void +destroy_physical_devices(struct vk_instance *instance) +{ + list_for_each_entry_safe(struct vk_physical_device, pdevice, + &instance->physical_devices.list, link) { + list_del(&pdevice->link); + instance->physical_devices.destroy(pdevice); + } +} + void vk_instance_finish(struct vk_instance *instance) { + destroy_physical_devices(instance); + glsl_type_singleton_decref(); if (unlikely(!list_is_empty(&instance->debug_utils.callbacks))) { list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, @@ -204,6 +229,7 @@ vk_instance_finish(struct vk_instance *instance) } mtx_destroy(&instance->debug_report.callbacks_mutex); mtx_destroy(&instance->debug_utils.callbacks_mutex); + mtx_destroy(&instance->physical_devices.mutex); vk_free(&instance->alloc, (char *)instance->app_info.app_name); vk_free(&instance->alloc, (char *)instance->app_info.engine_name); vk_object_base_finish(&instance->base); @@ -329,3 +355,119 @@ vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, instance->app_info.api_version, &instance->enabled_extensions); } + +static VkResult +enumerate_drm_physical_devices_locked(struct vk_instance *instance) +{ +#ifdef HAVE_LIBDRM + /* TODO: Check for more devices ? */ + drmDevicePtr devices[8]; + int max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); + + if (max_devices < 1) + return VK_SUCCESS; + + VkResult result; + for (uint32_t i = 0; i < (uint32_t)max_devices; i++) { + struct vk_physical_device *pdevice; + result = instance->physical_devices.try_create_for_drm(instance, devices[i], &pdevice); + + /* Incompatible DRM device, skip. */ + if (result == VK_ERROR_INCOMPATIBLE_DRIVER) { + result = VK_SUCCESS; + continue; + } + + /* Error creating the physical device, report the error. */ + if (result != VK_SUCCESS) + break; + + list_addtail(&pdevice->link, &instance->physical_devices.list); + } + + drmFreeDevices(devices, max_devices); + return result; +#endif + return VK_SUCCESS; +} + +static VkResult +enumerate_physical_devices_locked(struct vk_instance *instance) +{ + if (instance->physical_devices.enumerate) + return instance->physical_devices.enumerate(instance); + + VkResult result = VK_SUCCESS; + + if (instance->physical_devices.try_create_for_drm) { + result = enumerate_drm_physical_devices_locked(instance); + if (result != VK_SUCCESS) { + destroy_physical_devices(instance); + return result; + } + } + + return result; +} + +static VkResult +enumerate_physical_devices(struct vk_instance *instance) +{ + VkResult result = VK_SUCCESS; + + mtx_lock(&instance->physical_devices.mutex); + if (!instance->physical_devices.enumerated) { + result = enumerate_physical_devices_locked(instance); + if (result == VK_SUCCESS) + instance->physical_devices.enumerated = true; + } + mtx_unlock(&instance->physical_devices.mutex); + + return result; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_EnumeratePhysicalDevices(VkInstance _instance, uint32_t *pPhysicalDeviceCount, + VkPhysicalDevice *pPhysicalDevices) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices, pPhysicalDeviceCount); + + VkResult result = enumerate_physical_devices(instance); + if (result != VK_SUCCESS) + return result; + + list_for_each_entry(struct vk_physical_device, pdevice, + &instance->physical_devices.list, link) { + vk_outarray_append_typed(VkPhysicalDevice, &out, element) { + *element = vk_physical_device_to_handle(pdevice); + } + } + + return vk_outarray_status(&out); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_EnumeratePhysicalDeviceGroups(VkInstance _instance, uint32_t *pGroupCount, + VkPhysicalDeviceGroupProperties *pGroupProperties) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + VK_OUTARRAY_MAKE_TYPED(VkPhysicalDeviceGroupProperties, out, pGroupProperties, + pGroupCount); + + VkResult result = enumerate_physical_devices(instance); + if (result != VK_SUCCESS) + return result; + + list_for_each_entry(struct vk_physical_device, pdevice, + &instance->physical_devices.list, link) { + vk_outarray_append_typed(VkPhysicalDeviceGroupProperties, &out, p) { + p->physicalDeviceCount = 1; + memset(p->physicalDevices, 0, sizeof(p->physicalDevices)); + p->physicalDevices[0] = vk_physical_device_to_handle(pdevice); + p->subsetAllocation = false; + } + } + + return vk_outarray_status(&out); +} diff --git a/src/vulkan/runtime/vk_instance.h b/src/vulkan/runtime/vk_instance.h index 3609afc..af5b54b 100644 --- a/src/vulkan/runtime/vk_instance.h +++ b/src/vulkan/runtime/vk_instance.h @@ -55,6 +55,9 @@ struct vk_app_info { uint32_t api_version; }; +struct _drmDevice; +struct vk_physical_device; + /** Base struct for all `VkInstance` implementations * * This contains data structures necessary for detecting enabled extensions, @@ -101,6 +104,46 @@ struct vk_instance { /* Persistent callbacks */ struct list_head callbacks; } debug_utils; + + /** List of all physical devices and callbacks + * + * This is used for automatic physical device creation, + * deletion and enumeration. + */ + struct { + struct list_head list; + bool enumerated; + + /** Enumerate physical devices for this instance + * + * The driver can implement this callback for custom physical device + * enumeration. The callback should always return VK_SUCCESS unless + * an allocation failed. + * + * If this callback is not set, try_create_for_drm will be used for + * enumeration. + */ + VkResult (*enumerate)(struct vk_instance *instance); + + /** Try to create a physical device for a drm device + * + * For incompatible devices this callback should return + * VK_ERROR_INCOMPATIBLE_DRIVER. + */ + VkResult (*try_create_for_drm)(struct vk_instance *instance, + struct _drmDevice *device, + struct vk_physical_device **out); + + /** Handle the destruction of a physical device + * + * This callback has to be implemented when using common physical device + * management. The device pointer and any resource allocated for the + * device should be freed here. + */ + void (*destroy)(struct vk_physical_device *pdevice); + + mtx_t mutex; + } physical_devices; }; VK_DEFINE_HANDLE_CASTS(vk_instance, base, VkInstance, diff --git a/src/vulkan/runtime/vk_physical_device.h b/src/vulkan/runtime/vk_physical_device.h index eac023d..b047df1 100644 --- a/src/vulkan/runtime/vk_physical_device.h +++ b/src/vulkan/runtime/vk_physical_device.h @@ -27,6 +27,8 @@ #include "vk_extensions.h" #include "vk_object.h" +#include "util/list.h" + #ifdef __cplusplus extern "C" { #endif @@ -41,6 +43,9 @@ struct vk_pipeline_cache_object_ops; struct vk_physical_device { struct vk_object_base base; + /* See vk_instance::pdevices::list */ + struct list_head link; + /** Instance which is the parent of this physical device */ struct vk_instance *instance; -- 2.7.4