From 885d53a637e8f9e35f76b4b7e2ae1a9252ce680e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 12 May 2023 09:07:26 +0200 Subject: [PATCH] Vulkan: Extract Vendor/Driver/Device Information Extract vendor, driver and device information from the physical device properties. Note that driver version is implementation dependent and might fail as it is unclear which driver is being used. An open source driver could store the driver version in a different way than a closed source driver. But as it is not clear which driver version is being used it might extract the incorrect version. To solve this issue we check if the extracted version makes sense depending on the version schema of the driver and if they don't match we use another approach. --- source/blender/gpu/vulkan/vk_backend.cc | 56 ++++++--- source/blender/gpu/vulkan/vk_backend.hh | 9 +- source/blender/gpu/vulkan/vk_device.cc | 112 ++++++++++++++++-- source/blender/gpu/vulkan/vk_device.hh | 14 ++- .../blender/gpu/vulkan/vk_push_constants.cc | 7 +- .../blender/gpu/vulkan/vk_push_constants.hh | 10 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 2 +- 7 files changed, 164 insertions(+), 46 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index a9bd54d310f..3420e3bedc6 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -26,29 +26,53 @@ namespace blender::gpu { -void VKBackend::init_platform() +static eGPUOSType determine_os_type() { - BLI_assert(!GPG.initialized); +#ifdef _WIN32 + return GPU_OS_WIN; +#elif defined(__APPLE__) + return GPU_OS_MAC; +#else + return GPU_OS_UNIX; +#endif +} - eGPUDeviceType device = GPU_DEVICE_ANY; - eGPUOSType os = GPU_OS_ANY; +void VKBackend::platform_init() +{ + GPG.init(GPU_DEVICE_ANY, + determine_os_type(), + GPU_DRIVER_ANY, + GPU_SUPPORT_LEVEL_SUPPORTED, + GPU_BACKEND_VULKAN, + "", + "", + ""); +} + +void VKBackend::platform_init(const VKDevice &device) +{ + const VkPhysicalDeviceProperties &properties = device.physical_device_properties_get(); + + eGPUDeviceType device_type = device.device_type(); + eGPUOSType os = determine_os_type(); eGPUDriverType driver = GPU_DRIVER_ANY; eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED; -#ifdef _WIN32 - os = GPU_OS_WIN; -#elif defined(__APPLE__) - os = GPU_OS_MAC; -#else - os = GPU_OS_UNIX; -#endif + std::string vendor_name = device.vendor_name(); + std::string driver_version = device.driver_version(); - GPG.init(device, os, driver, support_level, GPU_BACKEND_VULKAN, "", "", ""); + GPG.init(device_type, + os, + driver, + support_level, + GPU_BACKEND_VULKAN, + vendor_name.c_str(), + properties.deviceName, + driver_version.c_str()); } void VKBackend::platform_exit() { - BLI_assert(GPG.initialized); GPG.clear(); } @@ -147,10 +171,10 @@ shaderc::Compiler &VKBackend::get_shaderc_compiler() return shaderc_compiler_; } -void VKBackend::capabilities_init() +void VKBackend::capabilities_init(const VKDevice &device) { - const VkPhysicalDeviceLimits &limits = - VKBackend::get().device_get().physical_device_limits_get(); + const VkPhysicalDeviceProperties &properties = device.physical_device_properties_get(); + const VkPhysicalDeviceLimits &limits = properties.limits; /* Reset all capabilities from previous context. */ GCaps = {}; diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh index 65599f9dfe3..39feeb952a0 100644 --- a/source/blender/gpu/vulkan/vk_backend.hh +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -36,7 +36,7 @@ class VKBackend : public GPUBackend { public: VKBackend() { - VKBackend::init_platform(); + platform_init(); } virtual ~VKBackend() @@ -76,8 +76,6 @@ class VKBackend : public GPUBackend { shaderc::Compiler &get_shaderc_compiler(); - static void capabilities_init(); - static VKBackend &get() { return *static_cast(GPUBackend::get()); @@ -88,8 +86,11 @@ class VKBackend : public GPUBackend { return device_; } + static void platform_init(const VKDevice &device); + static void capabilities_init(const VKDevice &device); + private: - static void init_platform(); + static void platform_init(); static void platform_exit(); /* These classes are allowed to modify the global device. */ diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index c396f277419..bd97850debd 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -24,7 +24,7 @@ void VKDevice::deinit() vk_device_ = VK_NULL_HANDLE; vk_queue_family_ = 0; vk_queue_ = VK_NULL_HANDLE; - vk_physical_device_limits_ = {}; + vk_physical_device_properties_ = {}; } bool VKDevice::is_initialized() const @@ -42,8 +42,9 @@ void VKDevice::init(void *ghost_context) &vk_queue_family_, &vk_queue_); - init_physical_device_limits(); - init_capabilities(); + init_physical_device_properties(); + VKBackend::platform_init(*this); + VKBackend::capabilities_init(*this); init_debug_callbacks(); init_memory_allocator(); init_descriptor_pools(); @@ -57,17 +58,10 @@ void VKDevice::init_debug_callbacks() debugging_tools_.init(vk_instance_); } -void VKDevice::init_physical_device_limits() +void VKDevice::init_physical_device_properties() { BLI_assert(vk_physical_device_ != VK_NULL_HANDLE); - VkPhysicalDeviceProperties properties = {}; - vkGetPhysicalDeviceProperties(vk_physical_device_, &properties); - vk_physical_device_limits_ = properties.limits; -} - -void VKDevice::init_capabilities() -{ - VKBackend::capabilities_init(); + vkGetPhysicalDeviceProperties(vk_physical_device_, &vk_physical_device_properties_); } void VKDevice::init_memory_allocator() @@ -87,4 +81,98 @@ void VKDevice::init_descriptor_pools() descriptor_pools_.init(vk_device_); } +/* -------------------------------------------------------------------- */ +/** \name Platform/driver/device information + * \{ */ + +constexpr int32_t PCI_ID_NVIDIA = 0x10de; +constexpr int32_t PCI_ID_INTEL = 0x8086; +constexpr int32_t PCI_ID_AMD = 0x1022; + +eGPUDeviceType VKDevice::device_type() const +{ + /* According to the vulkan specifications: + * + * If the vendor has a PCI vendor ID, the low 16 bits of vendorID must contain that PCI vendor + * ID, and the remaining bits must be set to zero. Otherwise, the value returned must be a valid + * Khronos vendor ID. + */ + switch (vk_physical_device_properties_.vendorID) { + case PCI_ID_NVIDIA: + return GPU_DEVICE_NVIDIA; + case PCI_ID_INTEL: + return GPU_DEVICE_INTEL; + case PCI_ID_AMD: + return GPU_DEVICE_ATI; + default: + break; + } + + return GPU_DEVICE_UNKNOWN; +} + +eGPUDriverType VKDevice::driver_type() const +{ + /* It is unclear how to determine the driver type, but it is required to extract the correct + * driver version. */ + return GPU_DRIVER_ANY; +} + +std::string VKDevice::vendor_name() const +{ + /* Below 0x10000 are the PCI vendor IDs (https://pcisig.com/membership/member-companies) */ + if (vk_physical_device_properties_.vendorID < 0x10000) { + switch (vk_physical_device_properties_.vendorID) { + case 0x1022: + return "Advanced Micro Devices"; + case 0x10DE: + return "NVIDIA Corporation"; + case 0x8086: + return "Intel Corporation"; + default: + return std::to_string(vk_physical_device_properties_.vendorID); + } + } + else { + /* above 0x10000 should be vkVendorIDs + * NOTE: When debug_messaging landed we can use something similar to + * vk::to_string(vk::VendorId(properties.vendorID)); + */ + return std::to_string(vk_physical_device_properties_.vendorID); + } +} + +std::string VKDevice::driver_version() const +{ + /* + * NOTE: this depends on the driver type and is currently incorrect. Idea is to use a default per + * OS. + */ + const uint32_t driver_version = vk_physical_device_properties_.driverVersion; + switch (vk_physical_device_properties_.vendorID) { + case PCI_ID_NVIDIA: + return std::to_string((driver_version >> 22) & 0x3FF) + "." + + std::to_string((driver_version >> 14) & 0xFF) + "." + + std::to_string((driver_version >> 6) & 0xFF) + "." + + std::to_string(driver_version & 0x3F); + case PCI_ID_INTEL: { + const uint32_t major = VK_VERSION_MAJOR(driver_version); + /* When using Mesa driver we should use VK_VERSION_*. */ + if (major > 30) { + return std::to_string((driver_version >> 14) & 0x3FFFF) + "." + + std::to_string((driver_version & 0x3FFF)); + } + break; + } + default: + break; + } + + return std::to_string(VK_VERSION_MAJOR(driver_version)) + "." + + std::to_string(VK_VERSION_MINOR(driver_version)) + "." + + std::to_string(VK_VERSION_PATCH(driver_version)); +} + +/** \} */ + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index c0df1ec703f..d386da44767 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -29,7 +29,7 @@ class VKDevice : public NonCopyable { VKDescriptorPools descriptor_pools_; /** Limits of the device linked to this context. */ - VkPhysicalDeviceLimits vk_physical_device_limits_; + VkPhysicalDeviceProperties vk_physical_device_properties_ = {}; /** Functions of vk_ext_debugutils for this device/instance. */ debug::VKDebuggingTools debugging_tools_; @@ -40,9 +40,9 @@ class VKDevice : public NonCopyable { return vk_physical_device_; } - const VkPhysicalDeviceLimits &physical_device_limits_get() const + const VkPhysicalDeviceProperties &physical_device_properties_get() const { - return vk_physical_device_limits_; + return vk_physical_device_properties_; } VkInstance instance_get() const @@ -89,9 +89,13 @@ class VKDevice : public NonCopyable { void init(void *ghost_context); void deinit(); + eGPUDeviceType device_type() const; + eGPUDriverType driver_type() const; + std::string vendor_name() const; + std::string driver_version() const; + private: - void init_physical_device_limits(); - void init_capabilities(); + void init_physical_device_properties(); void init_debug_callbacks(); void init_memory_allocator(); void init_descriptor_pools(); diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index c60e1d664e6..b30e7edd4cb 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -48,15 +48,16 @@ uint32_t struct_size(Span push_constants) } VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type( - const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits) + const shader::ShaderCreateInfo &info, const VKDevice &device) { if (info.push_constants_.is_empty()) { return StorageType::NONE; } + uint32_t max_push_constants_size = + device.physical_device_properties_get().limits.maxPushConstantsSize; uint32_t size = struct_size(info.push_constants_); - return size <= vk_physical_device_limits.maxPushConstantsSize ? STORAGE_TYPE_DEFAULT : - STORAGE_TYPE_FALLBACK; + return size <= max_push_constants_size ? STORAGE_TYPE_DEFAULT : STORAGE_TYPE_FALLBACK; } template diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index b13fce6cb1c..f39c81476c9 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -30,6 +30,7 @@ namespace blender::gpu { class VKShaderInterface; class VKUniformBuffer; class VKContext; +class VKDevice; /** * Container to store push constants in a buffer. @@ -88,17 +89,16 @@ class VKPushConstants : VKResourceTracker { public: /** * Return the desired storage type that can fit the push constants of the given shader create - * info, matching the device limits. + * info, matching the limits of the given device. * * Returns: * - StorageType::NONE: No push constants are needed. * - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used. * - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given - * device. A uniform buffer should be used as a fallback method. + * device. A uniform buffer should be used as a fallback method. */ - static StorageType determine_storage_type( - const shader::ShaderCreateInfo &info, - const VkPhysicalDeviceLimits &vk_physical_device_limits); + static StorageType determine_storage_type(const shader::ShaderCreateInfo &info, + const VKDevice &device); /** * Initialize the push constants of the given shader create info with the diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index a8fd996442b..c029cc043c5 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -50,7 +50,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) size_t names_size = info.interface_names_size_; const VKDevice &device = VKBackend::get().device_get(); const VKPushConstants::StorageType push_constants_storage_type = - VKPushConstants::Layout::determine_storage_type(info, device.physical_device_limits_get()); + VKPushConstants::Layout::determine_storage_type(info, device); if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { ubo_len_++; names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; -- 2.30.2