diff --git a/src/util/d3d11_device.cpp b/src/util/d3d11_device.cpp index 710de1e57..233fc2f07 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -122,14 +122,16 @@ bool D3D11Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature #endif ComPtr dxgi_device; + GPUDriverType driver_type = GPUDriverType::Unknown; if (SUCCEEDED(m_device.As(&dxgi_device)) && SUCCEEDED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.GetAddressOf())))) - INFO_LOG("D3D Adapter: {}", D3DCommon::GetAdapterName(dxgi_adapter.Get())); + INFO_LOG("D3D Adapter: {}", D3DCommon::GetAdapterName(dxgi_adapter.Get(), &driver_type)); else ERROR_LOG("Failed to obtain D3D adapter name."); INFO_LOG("Max device feature level: {}", D3DCommon::GetFeatureLevelString(D3DCommon::GetRenderAPIVersionForFeatureLevel(m_max_feature_level))); + SetDriverType(driver_type); SetFeatures(disabled_features); if (!wi.IsSurfaceless()) @@ -170,7 +172,7 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features) m_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, multisamples, &num_quality_levels)) && num_quality_levels > 0) { - m_max_multisamples = multisamples; + m_max_multisamples = static_cast(multisamples); } } diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index ff075502e..d63da21d2 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -263,6 +263,11 @@ bool D3D12Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature } } + GPUDriverType driver_type = GPUDriverType::Unknown; + if (std::string adapter_name = D3DCommon::GetAdapterName(m_adapter.Get(), &driver_type); adapter_name.empty()) + INFO_LOG("D3D Adapter: {}", adapter_name); + SetDriverType(driver_type); + const D3D12_COMMAND_QUEUE_DESC queue_desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE, 0u}; hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); @@ -1349,7 +1354,7 @@ void D3D12Device::SetFeatures(D3D_FEATURE_LEVEL feature_level, FeatureMask disab if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &fd, sizeof(fd))) && fd.NumQualityLevels > 0) { - m_max_multisamples = multisamples; + m_max_multisamples = static_cast(multisamples); } } diff --git a/src/util/d3d_common.cpp b/src/util/d3d_common.cpp index cc026aff8..8b4cbe3fa 100644 --- a/src/util/d3d_common.cpp +++ b/src/util/d3d_common.cpp @@ -178,7 +178,7 @@ GPUDevice::AdapterInfoList D3DCommon::GetAdapterInfoList() // Unfortunately we can't get any properties such as feature level without creating the device. // So just assume a max of the D3D11 max across the board. GPUDevice::AdapterInfo ai; - ai.name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get())); + ai.name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get(), &ai.driver_type)); ai.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; ai.max_multisamples = 8; ai.supports_sample_shading = true; @@ -352,7 +352,7 @@ Microsoft::WRL::ComPtr D3DCommon::GetChosenOrFirstAdapter(IDXGIFa return adapter; } -std::string D3DCommon::GetAdapterName(IDXGIAdapter1* adapter) +std::string D3DCommon::GetAdapterName(IDXGIAdapter1* adapter, GPUDriverType* out_driver_type) { std::string ret; @@ -361,10 +361,14 @@ std::string D3DCommon::GetAdapterName(IDXGIAdapter1* adapter) if (SUCCEEDED(hr)) { ret = StringUtil::WideStringToUTF8String(desc.Description); + if (out_driver_type) + *out_driver_type = GPUDevice::GuessDriverType(desc.VendorId, {}, ret); } else { ERROR_LOG("IDXGIAdapter1::GetDesc() returned {:08X}", static_cast(hr)); + if (out_driver_type) + *out_driver_type = GPUDriverType::Unknown; } if (ret.empty()) diff --git a/src/util/d3d_common.h b/src/util/d3d_common.h index 5360b847c..857bd4f9a 100644 --- a/src/util/d3d_common.h +++ b/src/util/d3d_common.h @@ -19,6 +19,8 @@ class Error; +enum class GPUDriverType : u16; + struct IDXGIFactory5; struct IDXGIAdapter; struct IDXGIAdapter1; @@ -57,7 +59,7 @@ Microsoft::WRL::ComPtr GetFirstAdapter(IDXGIFactory5* factory); Microsoft::WRL::ComPtr GetChosenOrFirstAdapter(IDXGIFactory5* factory, std::string_view name); // returns a utf-8 string of the specified adapter's name -std::string GetAdapterName(IDXGIAdapter1* adapter); +std::string GetAdapterName(IDXGIAdapter1* adapter, GPUDriverType* out_driver_type = nullptr); // returns the driver version from the registry as a string std::string GetDriverVersionFromLUID(const LUID& luid); diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index 85e9b81ec..0d941f572 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -1203,6 +1203,97 @@ void GPUDevice::ResetStatistics() s_stats = {}; } + +GPUDriverType GPUDevice::GuessDriverType(u32 pci_vendor_id, std::string_view vendor_name, std::string_view adapter_name) +{ +#define ACHECK(name) (adapter_name.find(name) != std::string_view::npos) +#define VCHECK(name) (vendor_name.find(name) != std::string_view::npos) +#define MESA_CHECK (ACHECK("Mesa") || VCHECK("Mesa")) + + if (pci_vendor_id == 0x1002 || pci_vendor_id == 0x1022 || VCHECK("Advanced Micro Devices") || + VCHECK("ATI Technologies Inc.") || VCHECK("ATI")) + { + INFO_LOG("AMD GPU detected."); + return MESA_CHECK ? GPUDriverType::AMDMesa : GPUDriverType::AMDProprietary; + } + else if (pci_vendor_id == 0x10DE || VCHECK("NVIDIA Corporation")) + { + INFO_LOG("NVIDIA GPU detected."); + return MESA_CHECK ? GPUDriverType::NVIDIAMesa : GPUDriverType::NVIDIAProprietary; + } + else if (pci_vendor_id == 0x8086 || VCHECK("Intel")) + { + INFO_LOG("Intel GPU detected."); + return MESA_CHECK ? GPUDriverType::IntelMesa : GPUDriverType::IntelProprietary; + } + else if (pci_vendor_id == 0x5143 || VCHECK("ARM") || ACHECK("Adreno")) + { + INFO_LOG("Qualcomm GPU detected."); + return MESA_CHECK ? GPUDriverType::QualcommMesa : GPUDriverType::QualcommProprietary; + } + else if (pci_vendor_id == 0x13B5 || VCHECK("ARM") || ACHECK("Mali")) + { + INFO_LOG("ARM GPU detected."); + return MESA_CHECK ? GPUDriverType::ARMMesa : GPUDriverType::ARMProprietary; + } + else if (pci_vendor_id == 0x1010 || VCHECK("Imagination Technologies") || ACHECK("PowerVR")) + { + INFO_LOG("Imagination GPU detected."); + return MESA_CHECK ? GPUDriverType::ImaginationMesa : GPUDriverType::ImaginationProprietary; + } + else if (pci_vendor_id == 0x14E4 || VCHECK("Broadcom") || ACHECK("VideoCore")) + { + INFO_LOG("Broadcom GPU detected."); + return MESA_CHECK ? GPUDriverType::BroadcomMesa : GPUDriverType::BroadcomProprietary; + } + else + { + WARNING_LOG("Unknown GPU vendor with PCI ID 0x{:04X}, adapter='{}', vendor='{}'", pci_vendor_id, adapter_name, + vendor_name); + return GPUDriverType::Unknown; + } + +#undef MESA_CHECK +#undef VCHECK +#undef ACHECK +} + +void GPUDevice::SetDriverType(GPUDriverType type) +{ + m_driver_type = type; + +#define NTENTRY(n) {GPUDriverType::n, #n} + static constexpr const std::pair name_table[] = { + NTENTRY(Unknown), + NTENTRY(AMDProprietary), + NTENTRY(AMDMesa), + NTENTRY(IntelProprietary), + NTENTRY(IntelMesa), + NTENTRY(NVIDIAProprietary), + NTENTRY(NVIDIAMesa), + NTENTRY(AppleProprietary), + NTENTRY(AppleMesa), + NTENTRY(DozenMesa), + + NTENTRY(ImaginationProprietary), + NTENTRY(ImaginationMesa), + NTENTRY(ARMProprietary), + NTENTRY(ARMMesa), + NTENTRY(QualcommProprietary), + NTENTRY(QualcommMesa), + NTENTRY(BroadcomProprietary), + NTENTRY(BroadcomMesa), + + NTENTRY(LLVMPipe), + NTENTRY(SwiftShader), + }; +#undef NTENTRY + + const auto iter = + std::find_if(std::begin(name_table), std::end(name_table), [&type](const auto& it) { return it.first == type; }); + INFO_LOG("Driver type set to {}.", (iter == std::end(name_table)) ? name_table[0].second : iter->second); +} + std::unique_ptr GPUDevice::CreateDeviceForAPI(RenderAPI api) { switch (api) diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index 04d1ccd38..40f6dc1a8 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -139,6 +139,36 @@ enum class GPUShaderLanguage : u8 Count }; +enum class GPUDriverType : u16 +{ + MobileFlag = 0x100, + SoftwareFlag = 0x200, + + Unknown = 0, + AMDProprietary = 1, + AMDMesa = 2, + IntelProprietary = 3, + IntelMesa = 4, + NVIDIAProprietary = 5, + NVIDIAMesa = 6, + AppleProprietary = 7, + AppleMesa = 8, + DozenMesa = 9, + + ImaginationProprietary = MobileFlag | 1, + ImaginationMesa = MobileFlag | 2, + ARMProprietary = MobileFlag | 3, + ARMMesa = MobileFlag | 4, + QualcommProprietary = MobileFlag | 5, + QualcommMesa = MobileFlag | 6, + BroadcomProprietary = MobileFlag | 7, + BroadcomMesa = MobileFlag | 8, + + LLVMPipe = SoftwareFlag | 1, + SwiftShader = SoftwareFlag | 2, +}; +IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(GPUDriverType); + class GPUShader { public: @@ -643,6 +673,7 @@ public: std::vector fullscreen_modes; u32 max_texture_size; u32 max_multisamples; + GPUDriverType driver_type; bool supports_sample_shading; }; using AdapterInfoList = std::vector; @@ -721,6 +752,9 @@ public: (count_z + (local_size_z - 1)) / local_size_z); } + /// Determines the driver type for a given adapter. + static GPUDriverType GuessDriverType(u32 pci_vendor_id, std::string_view vendor_name, std::string_view adapter_name); + ALWAYS_INLINE const Features& GetFeatures() const { return m_features; } ALWAYS_INLINE RenderAPI GetRenderAPI() const { return m_render_api; } ALWAYS_INLINE u32 GetRenderAPIVersion() const { return m_render_api_version; } @@ -926,11 +960,14 @@ protected: DynamicHeapArray* out_binary, Error* error); static std::optional> OptimizeVulkanSpv(const std::span spirv, Error* error); + void SetDriverType(GPUDriverType type); + Features m_features = {}; RenderAPI m_render_api = RenderAPI::None; u32 m_render_api_version = 0; u32 m_max_texture_size = 0; - u32 m_max_multisamples = 0; + GPUDriverType m_driver_type = GPUDriverType::Unknown; + u16 m_max_multisamples = 0; std::unique_ptr m_main_swap_chain; std::unique_ptr m_empty_texture; diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index 26d81370d..cb0c98d04 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -329,8 +329,11 @@ bool MetalDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature m_device = [device retain]; m_queue = [queue retain]; - INFO_LOG("Metal Device: {}", [[m_device name] UTF8String]); + const char* device_name = [[m_device name] UTF8String]; + INFO_LOG("Metal Device: {}", device_name); + + SetDriverType(GuessDriverType(0, {}, device_name)); SetFeatures(disabled_features); CreateCommandBuffer(); @@ -2797,11 +2800,13 @@ GPUDevice::AdapterInfoList GPUDevice::WrapGetMetalAdapterList() ret.reserve(count); for (u32 i = 0; i < count; i++) { + const char* device_name = [devices[i].name UTF8String]; AdapterInfo ai; - ai.name = [devices[i].name UTF8String]; + ai.name = device_name; ai.max_texture_size = GetMetalMaxTextureSize(devices[i]); ai.max_multisamples = GetMetalMaxMultisamples(devices[i]); ai.supports_sample_shading = true; + ai.driver_type = GuessDriverType(0, {}, device_name); ret.push_back(std::move(ai)); } } diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index f9c4ba2f0..7d68aa4e3 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -356,6 +356,8 @@ bool OpenGLDevice::CheckFeatures(FeatureMask disabled_features) const char* vendor = (const char*)glGetString(GL_VENDOR); const char* renderer = (const char*)glGetString(GL_RENDERER); + SetDriverType(GuessDriverType(0, vendor, renderer)); + if (std::strstr(vendor, "Advanced Micro Devices") || std::strstr(vendor, "ATI Technologies Inc.") || std::strstr(vendor, "ATI")) { @@ -404,7 +406,7 @@ bool OpenGLDevice::CheckFeatures(FeatureMask disabled_features) glGetIntegerv(GL_MAX_SAMPLES, &max_samples); DEV_LOG("GL_MAX_SAMPLES: {}", max_samples); m_max_texture_size = std::max(1024u, static_cast(max_texture_size)); - m_max_multisamples = std::max(1u, static_cast(max_samples)); + m_max_multisamples = static_cast(std::max(1u, static_cast(max_samples))); GLint max_dual_source_draw_buffers = 0; glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers); diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 6df557228..240fa4b8c 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -351,16 +351,29 @@ VulkanDevice::GPUList VulkanDevice::EnumerateGPUs(VkInstance instance) gpus.reserve(physical_devices.size()); for (VkPhysicalDevice device : physical_devices) { - VkPhysicalDeviceProperties props = {}; - vkGetPhysicalDeviceProperties(device, &props); + VkPhysicalDeviceProperties2 props = {}; + VkPhysicalDeviceDriverProperties driver_props = {}; + + if (vkGetPhysicalDeviceProperties2) + { + driver_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + Vulkan::AddPointerToChain(&props, &driver_props); + vkGetPhysicalDeviceProperties2(device, &props); + } + + // just in case the chained version fails + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + vkGetPhysicalDeviceProperties(device, &props.properties); VkPhysicalDeviceFeatures available_features = {}; vkGetPhysicalDeviceFeatures(device, &available_features); AdapterInfo ai; - ai.name = props.deviceName; - ai.max_texture_size = std::min(props.limits.maxFramebufferWidth, props.limits.maxImageDimension2D); - ai.max_multisamples = GetMaxMultisamples(device, props); + ai.name = props.properties.deviceName; + ai.max_texture_size = + std::min(props.properties.limits.maxFramebufferWidth, props.properties.limits.maxImageDimension2D); + ai.max_multisamples = GetMaxMultisamples(device, props.properties); + ai.driver_type = GuessDriverType(props.properties, driver_props); ai.supports_sample_shading = available_features.sampleRateShading; // handle duplicate adapter names @@ -600,6 +613,9 @@ bool VulkanDevice::EnableOptionalDeviceExtensions(VkPhysicalDevice physical_devi if (vkGetPhysicalDeviceProperties2 && properties2.pNext) vkGetPhysicalDeviceProperties2(physical_device, &properties2); + // set driver type + SetDriverType(GuessDriverType(m_device_properties, m_device_driver_properties)); + // check we actually support enough m_optional_extensions.vk_khr_push_descriptor &= (push_descriptor_properties.maxPushDescriptors >= 1); @@ -2501,7 +2517,7 @@ void VulkanDevice::SetFeatures(FeatureMask disabled_features, VkPhysicalDevice p (VK_API_VERSION_MINOR(store_api_version) * 10u) + (VK_API_VERSION_PATCH(store_api_version)); m_max_texture_size = std::min(m_device_properties.limits.maxImageDimension2D, m_device_properties.limits.maxFramebufferWidth); - m_max_multisamples = GetMaxMultisamples(physical_device, m_device_properties); + m_max_multisamples = static_cast(GetMaxMultisamples(physical_device, m_device_properties)); m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && vk_features.dualSrcBlend; m_features.framebuffer_fetch = @@ -2552,6 +2568,51 @@ void VulkanDevice::SetFeatures(FeatureMask disabled_features, VkPhysicalDevice p (!(disabled_features & FEATURE_MASK_COMPRESSED_TEXTURES) && vk_features.textureCompressionBC); } +GPUDriverType VulkanDevice::GuessDriverType(const VkPhysicalDeviceProperties& device_properties, + const VkPhysicalDeviceDriverProperties& driver_properties) +{ + static constexpr const std::pair table[] = { + {VK_DRIVER_ID_NVIDIA_PROPRIETARY, GPUDriverType::NVIDIAProprietary}, + {VK_DRIVER_ID_AMD_PROPRIETARY, GPUDriverType::AMDProprietary}, + {VK_DRIVER_ID_AMD_OPEN_SOURCE, GPUDriverType::AMDProprietary}, + {VK_DRIVER_ID_MESA_RADV, GPUDriverType::AMDMesa}, + {VK_DRIVER_ID_NVIDIA_PROPRIETARY, GPUDriverType::NVIDIAProprietary}, + {VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, GPUDriverType::IntelProprietary}, + {VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, GPUDriverType::IntelMesa}, + {VK_DRIVER_ID_IMAGINATION_PROPRIETARY, GPUDriverType::ImaginationProprietary}, + {VK_DRIVER_ID_QUALCOMM_PROPRIETARY, GPUDriverType::QualcommProprietary}, + {VK_DRIVER_ID_ARM_PROPRIETARY, GPUDriverType::ARMProprietary}, + {VK_DRIVER_ID_GOOGLE_SWIFTSHADER, GPUDriverType::SwiftShader}, + {VK_DRIVER_ID_GGP_PROPRIETARY, GPUDriverType::Unknown}, + {VK_DRIVER_ID_BROADCOM_PROPRIETARY, GPUDriverType::BroadcomProprietary}, + {VK_DRIVER_ID_MESA_LLVMPIPE, GPUDriverType::LLVMPipe}, + {VK_DRIVER_ID_MOLTENVK, GPUDriverType::AppleProprietary}, + {VK_DRIVER_ID_COREAVI_PROPRIETARY, GPUDriverType::Unknown}, + {VK_DRIVER_ID_JUICE_PROPRIETARY, GPUDriverType::Unknown}, + {VK_DRIVER_ID_VERISILICON_PROPRIETARY, GPUDriverType::Unknown}, + {VK_DRIVER_ID_MESA_TURNIP, GPUDriverType::QualcommMesa}, + {VK_DRIVER_ID_MESA_V3DV, GPUDriverType::BroadcomMesa}, + {VK_DRIVER_ID_MESA_PANVK, GPUDriverType::ARMMesa}, + {VK_DRIVER_ID_SAMSUNG_PROPRIETARY, GPUDriverType::AMDProprietary}, + {VK_DRIVER_ID_MESA_VENUS, GPUDriverType::Unknown}, + {VK_DRIVER_ID_MESA_DOZEN, GPUDriverType::DozenMesa}, + {VK_DRIVER_ID_MESA_NVK, GPUDriverType::NVIDIAMesa}, + {VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA, GPUDriverType::ImaginationMesa}, + {VK_DRIVER_ID_MESA_AGXV, GPUDriverType::AppleMesa}, + }; + + const auto iter = std::find_if(std::begin(table), std::end(table), [&driver_properties](const auto& it) { + return (driver_properties.driverID == it.first); + }); + if (iter != std::end(table)) + return iter->second; + + return GPUDevice::GuessDriverType( + device_properties.vendorID, {}, + std::string_view(device_properties.deviceName, + StringUtil::Strnlen(device_properties.deviceName, std::size(device_properties.deviceName)))); +} + void VulkanDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index e270224e1..8a284c2f7 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -349,6 +349,8 @@ private: void SetFeatures(FeatureMask disabled_features, VkPhysicalDevice physical_device, const VkPhysicalDeviceFeatures& vk_features); + static GPUDriverType GuessDriverType(const VkPhysicalDeviceProperties& device_properties, + const VkPhysicalDeviceDriverProperties& driver_properties); static u32 GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties); bool CreateAllocator(); @@ -432,7 +434,7 @@ private: VkDebugUtilsMessengerEXT m_debug_messenger_callback = VK_NULL_HANDLE; VkPhysicalDeviceProperties m_device_properties = {}; - VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {}; + VkPhysicalDeviceDriverProperties m_device_driver_properties = {}; OptionalExtensions m_optional_extensions = {}; std::optional m_exclusive_fullscreen_control;