From 52c89fbbd7e24170916051ab65c4aa967bdb9d31 Mon Sep 17 00:00:00 2001 From: CrystalP Date: Mon, 20 May 2024 11:41:17 -0400 Subject: [PATCH] [Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10 Add detection for recent drivers through DXGI only Add secondary registry detection method for older drivers that fail the traditional method --- xbmc/platform/win32/WIN32Util.cpp | 128 +++++++++++++++++++++++++++++----- xbmc/platform/win32/WIN32Util.h | 6 ++ xbmc/rendering/dx/DeviceResources.cpp | 31 ++++---- xbmc/rendering/dx/DeviceResources.h | 2 +- 4 files changed, 136 insertions(+), 31 deletions(-) diff --git a/xbmc/platform/win32/WIN32Util.cpp b/xbmc/platform/win32/WIN32Util.cpp index cfabcf3e6f..29658a42a9 100644 --- a/xbmc/platform/win32/WIN32Util.cpp +++ b/xbmc/platform/win32/WIN32Util.cpp @@ -32,6 +32,7 @@ #endif #include #include +#include #include #include @@ -60,6 +61,21 @@ using namespace winrt::Windows::Graphics::Display::Core; using namespace winrt::Windows::Storage; #endif +void VideoDriverInfo::Log() +{ + if (!valid) + { + CLog::LogF(LOGERROR, "video driver version information is not valid"); + return; + } + + if (vendorId == PCIV_NVIDIA) + CLog::LogF(LOGINFO, "video driver version is {} {}.{} ({})", DX::GetGFXProviderName(vendorId), + majorVersion, minorVersion, version); + else + CLog::LogF(LOGINFO, "video driver version is {} {}", DX::GetGFXProviderName(vendorId), version); +} + CWIN32Util::CWIN32Util(void) { } @@ -1601,7 +1617,6 @@ VideoDriverInfo CWIN32Util::GetVideoDriverInfo(const UINT vendorId, const std::w subkey.append(L"\\"); subkey.append(L"0000"); DWORD lg; - wchar_t desc[128] = {}; lg = sizeof(desc); if (ERROR_SUCCESS != RegGetValueW(HKEY_LOCAL_MACHINE, subkey.c_str(), L"DriverDesc", @@ -1613,27 +1628,15 @@ VideoDriverInfo CWIN32Util::GetVideoDriverInfo(const UINT vendorId, const std::w continue; // driver of interest found, we read version - wchar_t version[64] = {}; - lg = sizeof(version); + wchar_t wversion[64] = {}; + lg = sizeof(wversion); if (ERROR_SUCCESS != RegGetValueW(HKEY_LOCAL_MACHINE, subkey.c_str(), L"DriverVersion", - RRF_RT_REG_SZ, nullptr, version, &lg)) + RRF_RT_REG_SZ, nullptr, wversion, &lg)) continue; - info.valid = true; - info.version = FromW(std::wstring(version)); + const std::string version = FromW(std::wstring(wversion)); - // convert driver store version to Nvidia version - if (vendorId == PCIV_NVIDIA) - { - std::string ver(info.version); - StringUtils::Replace(ver, ".", ""); - info.majorVersion = std::stoi(ver.substr(ver.length() - 5, 3)); - info.minorVersion = std::stoi(ver.substr(ver.length() - 2, 2)); - } - else // for Intel/AMD fill major version only. Single-digit for WDDM < 1.3. - { - info.majorVersion = std::stoi(info.version.substr(0, info.version.find('.'))); - } + info = FormatVideoDriverInfo(vendorId, version); } while (sta == ERROR_SUCCESS && !info.valid); @@ -1643,6 +1646,95 @@ VideoDriverInfo CWIN32Util::GetVideoDriverInfo(const UINT vendorId, const std::w return info; } +VideoDriverInfo CWIN32Util::GetVideoDriverInfoDX(const UINT vendorId, LUID adapterLuid) +{ + VideoDriverInfo info = {}; + +#ifdef TARGET_WINDOWS_DESKTOP + HKEY hKey = nullptr; + const wchar_t* SUBKEY = L"SOFTWARE\\Microsoft\\DirectX"; + + if (ERROR_SUCCESS != RegOpenKeyExW(HKEY_LOCAL_MACHINE, SUBKEY, 0, KEY_ENUMERATE_SUB_KEYS, &hKey)) + return {}; + + LSTATUS sta = ERROR_SUCCESS; + wchar_t keyName[128] = {}; + DWORD index = 0; + DWORD len; + + using KODI::PLATFORM::WINDOWS::FromW; + + do + { + len = sizeof(keyName) / sizeof(wchar_t); + sta = RegEnumKeyExW(hKey, index, keyName, &len, nullptr, nullptr, nullptr, nullptr); + index++; + + if (sta != ERROR_SUCCESS) + continue; + + LUID luid = {}; + DWORD qwordSize = sizeof(luid); + + if (ERROR_SUCCESS != + RegGetValueW(hKey, keyName, L"AdapterLuid", RRF_RT_QWORD, nullptr, &luid, &qwordSize)) + continue; + + if (luid.HighPart != adapterLuid.HighPart || luid.LowPart != adapterLuid.LowPart) + continue; + + // driver of interest found, read the version + uint64_t rawDriverVersion{}; + if (ERROR_SUCCESS != RegGetValueW(hKey, keyName, L"DriverVersion", RRF_RT_QWORD, nullptr, + &rawDriverVersion, &qwordSize)) + continue; + + info = FormatVideoDriverInfo(vendorId, rawDriverVersion); + + } while (sta == ERROR_SUCCESS && !info.valid); + + RegCloseKey(hKey); +#endif + + return info; +} + +VideoDriverInfo CWIN32Util::FormatVideoDriverInfo(const UINT vendorId, uint64_t rawVersion) +{ + const unsigned int part1 = static_cast(rawVersion >> 48); + const unsigned int part2 = static_cast((rawVersion >> 32) & 0xFFFF); + const unsigned int part3 = static_cast((rawVersion >> 16) & 0xFFFF); + const unsigned int part4 = static_cast(rawVersion & 0xFFFF); + + std::ostringstream ss; + ss << part1 << '.' << part2 << '.' << part3 << '.' << part4; + + return FormatVideoDriverInfo(vendorId, ss.str()); +} + +VideoDriverInfo CWIN32Util::FormatVideoDriverInfo(const UINT vendorId, const std::string version) +{ + VideoDriverInfo info = {}; + + info.valid = true; + info.vendorId = vendorId; + info.version = version; + + // convert driver store version to Nvidia version + if (vendorId == PCIV_NVIDIA) + { + std::string ver(version); + StringUtils::Replace(ver, ".", ""); + info.majorVersion = std::stoi(ver.substr(ver.length() - 5, 3)); + info.minorVersion = std::stoi(ver.substr(ver.length() - 2, 2)); + } + else // for Intel/AMD fill major version only + { + info.majorVersion = std::stoi(version.substr(0, version.find('.'))); + } + return info; +} + std::wstring CWIN32Util::GetDisplayFriendlyName(const std::wstring& gdiDeviceName) { #ifdef TARGET_WINDOWS_STORE diff --git a/xbmc/platform/win32/WIN32Util.h b/xbmc/platform/win32/WIN32Util.h index 1b806d5161..054ca262bd 100644 --- a/xbmc/platform/win32/WIN32Util.h +++ b/xbmc/platform/win32/WIN32Util.h @@ -22,10 +22,13 @@ struct VideoDriverInfo { + UINT vendorId; int majorVersion; int minorVersion; bool valid; std::string version; + + void Log(); }; class CURL; // forward declaration @@ -83,6 +86,9 @@ public: static void PlatformSyslog(); static VideoDriverInfo GetVideoDriverInfo(const UINT vendorId, const std::wstring& driverDesc); + static VideoDriverInfo GetVideoDriverInfoDX(const UINT vendorId, LUID adapterLuid); + static VideoDriverInfo FormatVideoDriverInfo(const UINT vendorId, uint64_t rawVersion); + static VideoDriverInfo FormatVideoDriverInfo(const UINT vendorId, const std::string version); static std::wstring GetDisplayFriendlyName(const std::wstring& GdiDeviceName); /*! * \brief Set the thread name using SetThreadDescription when available diff --git a/xbmc/rendering/dx/DeviceResources.cpp b/xbmc/rendering/dx/DeviceResources.cpp index 444e804c8b..8fe7d5e412 100644 --- a/xbmc/rendering/dx/DeviceResources.cpp +++ b/xbmc/rendering/dx/DeviceResources.cpp @@ -1168,6 +1168,7 @@ void DX::DeviceResources::CheckDXVA2SharedDecoderSurfaces() return; VideoDriverInfo driver = GetVideoDriverVersion(); + driver.Log(); if (!m_NV12SharedTexturesSupport) return; @@ -1200,18 +1201,26 @@ void DX::DeviceResources::CheckDXVA2SharedDecoderSurfaces() CLog::LogF(LOGINFO, "DXVA Video Super Resolution is potentially supported"); } -VideoDriverInfo DX::DeviceResources::GetVideoDriverVersion() +VideoDriverInfo DX::DeviceResources::GetVideoDriverVersion() const { + if (!m_adapter) + return {}; + + VideoDriverInfo driver{}; const DXGI_ADAPTER_DESC ad = GetAdapterDesc(); - const VideoDriverInfo driver = CWIN32Util::GetVideoDriverInfo(ad.VendorId, ad.Description); + // Version retrieval with DXGI is more modern but requires WDDM >= 2.3 for guarantee of same + // version returned by all driver components. Fallback to older method for older drivers. + LARGE_INTEGER rawVersion{}; + if (SUCCEEDED(m_adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &rawVersion)) && + static_cast(rawVersion.QuadPart >> 48) >= 23) + driver = CWIN32Util::FormatVideoDriverInfo(ad.VendorId, rawVersion.QuadPart); - if (ad.VendorId == PCIV_NVIDIA) - CLog::LogF(LOGINFO, "video driver version is {} {}.{} ({})", GetGFXProviderName(ad.VendorId), - driver.majorVersion, driver.minorVersion, driver.version); - else - CLog::LogF(LOGINFO, "video driver version is {} {}", GetGFXProviderName(ad.VendorId), - driver.version); + if (!driver.valid) + driver = CWIN32Util::GetVideoDriverInfo(ad.VendorId, ad.Description); + + if (!driver.valid) + driver = CWIN32Util::GetVideoDriverInfoDX(ad.VendorId, ad.AdapterLuid); return driver; } @@ -1490,13 +1499,11 @@ bool DX::DeviceResources::IsGCNOrOlder() const if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::Xbox) return false; - const DXGI_ADAPTER_DESC ad = GetAdapterDesc(); + const VideoDriverInfo driver = GetVideoDriverVersion(); - if (ad.VendorId != PCIV_AMD) + if (driver.vendorId != PCIV_AMD) return false; - const VideoDriverInfo driver = CWIN32Util::GetVideoDriverInfo(ad.VendorId, ad.Description); - if (driver.valid && CWIN32Util::IsDriverVersionAtLeast(driver.version, "31.0.22000.0")) return false; diff --git a/xbmc/rendering/dx/DeviceResources.h b/xbmc/rendering/dx/DeviceResources.h index fe378dd40a..b0ed0f4882 100644 --- a/xbmc/rendering/dx/DeviceResources.h +++ b/xbmc/rendering/dx/DeviceResources.h @@ -150,7 +150,7 @@ namespace DX void HandleOutputChange(const std::function& cmpFunc); bool CreateFactory(); void CheckNV12SharedTexturesSupport(); - VideoDriverInfo GetVideoDriverVersion(); + VideoDriverInfo GetVideoDriverVersion() const; void CheckDXVA2SharedDecoderSurfaces(); HWND m_window{ nullptr }; -- 2.11.4.GIT