GPUDevice: Backport driver type detection

This commit is contained in:
Stenzek 2025-07-09 22:12:49 +10:00
parent 1e930c4063
commit ef26d5cb74
No known key found for this signature in database
10 changed files with 228 additions and 17 deletions

View File

@ -122,14 +122,16 @@ bool D3D11Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature
#endif
ComPtr<IDXGIDevice> 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<u16>(multisamples);
}
}

View File

@ -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<u16>(multisamples);
}
}

View File

@ -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<IDXGIAdapter1> 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<unsigned>(hr));
if (out_driver_type)
*out_driver_type = GPUDriverType::Unknown;
}
if (ret.empty())

View File

@ -19,6 +19,8 @@
class Error;
enum class GPUDriverType : u16;
struct IDXGIFactory5;
struct IDXGIAdapter;
struct IDXGIAdapter1;
@ -57,7 +59,7 @@ Microsoft::WRL::ComPtr<IDXGIAdapter1> GetFirstAdapter(IDXGIFactory5* factory);
Microsoft::WRL::ComPtr<IDXGIAdapter1> 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);

View File

@ -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<GPUDriverType, const char*> 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> GPUDevice::CreateDeviceForAPI(RenderAPI api)
{
switch (api)

View File

@ -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<ExclusiveFullscreenMode> fullscreen_modes;
u32 max_texture_size;
u32 max_multisamples;
GPUDriverType driver_type;
bool supports_sample_shading;
};
using AdapterInfoList = std::vector<AdapterInfo>;
@ -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<u8>* out_binary, Error* error);
static std::optional<DynamicHeapArray<u8>> OptimizeVulkanSpv(const std::span<const u8> 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<GPUSwapChain> m_main_swap_chain;
std::unique_ptr<GPUTexture> m_empty_texture;

View File

@ -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));
}
}

View File

@ -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<u32>(max_texture_size));
m_max_multisamples = std::max(1u, static_cast<u32>(max_samples));
m_max_multisamples = static_cast<u16>(std::max(1u, static_cast<u32>(max_samples)));
GLint max_dual_source_draw_buffers = 0;
glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers);

View File

@ -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<u16>(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<VkDriverId, GPUDriverType> 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)

View File

@ -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<bool> m_exclusive_fullscreen_control;