Commit 1241aea5 authored by Olli Etuaho's avatar Olli Etuaho Committed by Commit Bot

Get NVIDIA driver version from NVML on 64-bit Windows

NVML provides a more reliable way to query for the NVIDIA driver
version. It also provides a query for NVIDIA CUDA compute capability
which corresponds to the GPU generation. This is a good value to use
for filtering GPUs based on hardware properties.

We now query NVML for driver version and CUDA compute capability in
case an NVIDIA GPU is encountered on Windows. NVML is loaded
dynamically from %ProgramW6432%/NVIDIA Corporation/NVSMI/nvml.dll.
In recent drivers the library is only shipped as a 64-bit binary, so
it won't load in case the 32-bit build of Chromium is used.

As a fallback, the actual NVIDIA driver version is parsed from the
driver version in the Windows registry. This best-effort parsing
should work for most versions, though every single version may not
conform to the expected format.

NVML has been present in NVIDIA drivers since version 270 published in
2011. Some functionality in NVML is exclusive to professional Quadro
or Tesla GPUs, but basic functionality like the queries used here are
available across NVIDIA GPU brands.

BUG=693090

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I31b44021e00426fcfb2b850fea5d63c114c4569c
Reviewed-on: https://chromium-review.googlesource.com/1108199Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Cr-Commit-Position: refs/heads/master@{#581820}
parent b4ce470b
...@@ -226,6 +226,9 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue( ...@@ -226,6 +226,9 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
NewDescriptionValuePair("Driver version", active_gpu.driver_version)); NewDescriptionValuePair("Driver version", active_gpu.driver_version));
basic_info->Append( basic_info->Append(
NewDescriptionValuePair("Driver date", active_gpu.driver_date)); NewDescriptionValuePair("Driver date", active_gpu.driver_date));
basic_info->Append(NewDescriptionValuePair(
"GPU CUDA compute capability major version",
std::make_unique<base::Value>(active_gpu.cuda_compute_capability_major)));
basic_info->Append(NewDescriptionValuePair("Pixel shader version", basic_info->Append(NewDescriptionValuePair("Pixel shader version",
gpu_info.pixel_shader_version)); gpu_info.pixel_shader_version));
basic_info->Append(NewDescriptionValuePair("Vertex shader version", basic_info->Append(NewDescriptionValuePair("Vertex shader version",
......
include_rules = [ include_rules = [
"+third_party/angle", "+third_party/angle",
"+third_party/amd", "+third_party/amd",
"+third_party/nvml",
"+third_party/re2", "+third_party/re2",
"+third_party/smhasher", "+third_party/smhasher",
"+third_party/swiftshader", "+third_party/swiftshader",
......
...@@ -168,6 +168,12 @@ source_set("config_sources") { ...@@ -168,6 +168,12 @@ source_set("config_sources") {
"setupapi.lib", "setupapi.lib",
] ]
sources += [
"//third_party/nvml/nvml.h",
"nvml_info.cc",
"nvml_info.h",
]
if (is_chrome_branded && is_official_build) { if (is_chrome_branded && is_official_build) {
sources += [ sources += [
"//third_party/amd/AmdCfxPxExt.h", "//third_party/amd/AmdCfxPxExt.h",
......
...@@ -489,7 +489,7 @@ ...@@ -489,7 +489,7 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "<=", "op": "<=",
"value": "8.17.12.6973" "value": "269.73"
}, },
"features": [ "features": [
"disable_d3d11" "disable_d3d11"
...@@ -1850,7 +1850,7 @@ ...@@ -1850,7 +1850,7 @@
}, },
"driver_version": { "driver_version": {
"op": "<", "op": "<",
"value": "21.21.13.7576" "value": "375.76"
}, },
"vendor_id": "0x10de", "vendor_id": "0x10de",
"features": [ "features": [
......
...@@ -19,6 +19,8 @@ void EnumerateGPUDevice(const gpu::GPUInfo::GPUDevice& device, ...@@ -19,6 +19,8 @@ void EnumerateGPUDevice(const gpu::GPUInfo::GPUDevice& device,
enumerator->AddString("driverVendor", device.driver_vendor); enumerator->AddString("driverVendor", device.driver_vendor);
enumerator->AddString("driverVersion", device.driver_version); enumerator->AddString("driverVersion", device.driver_version);
enumerator->AddString("driverDate", device.driver_date); enumerator->AddString("driverDate", device.driver_date);
enumerator->AddInt("cudaComputeCapabilityMajor",
device.cuda_compute_capability_major);
enumerator->EndGPUDevice(); enumerator->EndGPUDevice();
} }
...@@ -94,8 +96,8 @@ VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() = ...@@ -94,8 +96,8 @@ VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() =
GPUInfo::GPUDevice::GPUDevice() GPUInfo::GPUDevice::GPUDevice()
: vendor_id(0), : vendor_id(0),
device_id(0), device_id(0),
active(false) { active(false),
} cuda_compute_capability_major(0) {}
GPUInfo::GPUDevice::GPUDevice(const GPUInfo::GPUDevice& other) = default; GPUInfo::GPUDevice::GPUDevice(const GPUInfo::GPUDevice& other) = default;
......
...@@ -137,6 +137,10 @@ struct GPU_EXPORT GPUInfo { ...@@ -137,6 +137,10 @@ struct GPU_EXPORT GPUInfo {
std::string driver_vendor; std::string driver_vendor;
std::string driver_version; std::string driver_version;
std::string driver_date; std::string driver_date;
// NVIDIA CUDA compute capability, major version. 0 if undetermined. Can be
// used to determine the hardware generation that the GPU belongs to.
int cuda_compute_capability_major;
}; };
GPUInfo(); GPUInfo();
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "base/win/scoped_com_initializer.h" #include "base/win/scoped_com_initializer.h"
#include "gpu/config/nvml_info.h"
#include "third_party/vulkan/include/vulkan/vulkan.h" #include "third_party/vulkan/include/vulkan/vulkan.h"
namespace gpu { namespace gpu {
...@@ -124,6 +125,28 @@ bool GetAMDSwitchableInfo(bool* is_switchable, ...@@ -124,6 +125,28 @@ bool GetAMDSwitchableInfo(bool* is_switchable,
} }
#endif #endif
std::string ParseNVIDIARegistryDriverVersion(std::string registry_version) {
// The NVIDIA driver version in the registry is most commonly in the format:
// XX.XX.XD.DDDD
// Where "X" corresponds to an OS-specific digit and "D" corresponds to a
// digit of the actual driver version. We convert it to the following format:
// DDD.DD
// This matches with the actual driver version that NVML also returns.
std::string second_to_last_digits;
std::string last_digits;
if (!RE2::FullMatch(registry_version, "\\d+\\.\\d+\\.(\\d+)\\.(\\d+)",
&second_to_last_digits, &last_digits)) {
return registry_version;
}
std::string digits = second_to_last_digits + last_digits;
if (digits.length() < 5u) {
return registry_version;
}
digits.erase(0, digits.length() - 5u);
DCHECK(digits.length() == 5u);
return digits.substr(0u, 3u) + "." + digits.substr(3u);
}
bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) { bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
...@@ -199,6 +222,28 @@ bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) { ...@@ -199,6 +222,28 @@ bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
found_intel = true; found_intel = true;
if (device.vendor_id == 0x1002) if (device.vendor_id == 0x1002)
found_amd = true; found_amd = true;
if (device.vendor_id == 0x10de) {
std::string nvml_driver_version;
int major_cuda_compute_capability = 0;
int minor_cuda_compute_capability = 0;
bool nvml_success = GetNvmlDeviceInfo(
device.device_id, &nvml_driver_version,
&major_cuda_compute_capability, &minor_cuda_compute_capability);
if (nvml_success) {
// We use the NVML driver version instead of the registry version,
// since the registry version includes OS-specific digits that are
// not part of the actual driver version.
device.driver_version = nvml_driver_version;
device.cuda_compute_capability_major =
major_cuda_compute_capability;
} else {
// If we can't get the actual driver version from NVML, do
// best-effort parsing of the actual driver version from the
// registry driver version.
device.driver_version =
ParseNVIDIARegistryDriverVersion(device.driver_version);
}
}
devices.push_back(device); devices.push_back(device);
} }
......
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/config/nvml_info.h"
#include <windows.h>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "third_party/nvml/nvml.h"
namespace {
const unsigned int kDriverVersionCapacity = 80u;
} // anonymous namespace
typedef decltype(&nvmlInit) INITPROC;
typedef decltype(&nvmlShutdown) SHUTDOWNPROC;
typedef decltype(&nvmlSystemGetDriverVersion) GETDRIVERVERSIONPROC;
typedef decltype(&nvmlDeviceGetCount) DEVICEGETCOUNTPROC;
typedef decltype(&nvmlDeviceGetHandleByIndex) DEVICEGETHANDLEBYINDEXPROC;
typedef decltype(&nvmlDeviceGetPciInfo) DEVICEGETPCIINFOPROC;
typedef decltype(
&nvmlDeviceGetCudaComputeCapability) DEVICEGETCUDACOMPUTECAPABILITYPROC;
bool GetNvmlDeviceInfo(uint32_t pci_device_id,
std::string* driver_version,
int* major_cuda_compute_capability,
int* minor_cuda_compute_capability) {
DCHECK(major_cuda_compute_capability);
DCHECK(minor_cuda_compute_capability);
*major_cuda_compute_capability = 0;
*minor_cuda_compute_capability = 0;
base::FilePath dll_path;
if (!base::PathService::Get(base::DIR_PROGRAM_FILES6432, &dll_path)) {
return false;
}
dll_path = dll_path.Append(L"NVIDIA Corporation\\NVSMI\\nvml.dll");
HINSTANCE hinstNVML = LoadLibrary(dll_path.value().data());
if (!hinstNVML) {
return false;
}
INITPROC fnNvmlInit = (INITPROC)GetProcAddress(hinstNVML, "nvmlInit");
SHUTDOWNPROC fnNvmlShutdown =
(SHUTDOWNPROC)GetProcAddress(hinstNVML, "nvmlShutdown");
GETDRIVERVERSIONPROC fnNvmlSystemGetDriverVersion =
(GETDRIVERVERSIONPROC)GetProcAddress(hinstNVML,
"nvmlSystemGetDriverVersion");
DEVICEGETCOUNTPROC fnNvmlDeviceGetCount =
(DEVICEGETCOUNTPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetCount");
DEVICEGETHANDLEBYINDEXPROC fnNvmlDeviceGetHandleByIndex =
(DEVICEGETHANDLEBYINDEXPROC)GetProcAddress(hinstNVML,
"nvmlDeviceGetHandleByIndex");
DEVICEGETPCIINFOPROC fnNvmlDeviceGetPciInfo =
(DEVICEGETPCIINFOPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetPciInfo");
DEVICEGETCUDACOMPUTECAPABILITYPROC fnNvmlDeviceGetCudaComputeCapability =
(DEVICEGETCUDACOMPUTECAPABILITYPROC)GetProcAddress(
hinstNVML, "nvmlDeviceGetCudaComputeCapability");
if (!fnNvmlInit || !fnNvmlShutdown || !fnNvmlSystemGetDriverVersion) {
return false;
}
nvmlReturn_t result = fnNvmlInit();
if (NVML_SUCCESS != result) {
return false;
}
char driver_version_temp[kDriverVersionCapacity];
result =
fnNvmlSystemGetDriverVersion(driver_version_temp, kDriverVersionCapacity);
if (NVML_SUCCESS != result) {
fnNvmlShutdown();
return false;
}
*driver_version = driver_version_temp;
if (fnNvmlDeviceGetCount && fnNvmlDeviceGetHandleByIndex &&
fnNvmlDeviceGetPciInfo && fnNvmlDeviceGetCudaComputeCapability) {
unsigned int device_count;
result = fnNvmlDeviceGetCount(&device_count);
if (NVML_SUCCESS == result) {
for (unsigned int i = 0; i < device_count; i++) {
nvmlDevice_t device;
nvmlPciInfo_t pci;
result = fnNvmlDeviceGetHandleByIndex(i, &device);
if (NVML_SUCCESS != result) {
continue;
}
result = fnNvmlDeviceGetPciInfo(device, &pci);
if (NVML_SUCCESS != result) {
continue;
}
// We're looking for a particular PCI device.
if (pci.pciDeviceId != ((pci_device_id << 16) | 0x10deu)) {
continue;
}
result = fnNvmlDeviceGetCudaComputeCapability(
device, major_cuda_compute_capability,
minor_cuda_compute_capability);
if (NVML_SUCCESS != result) {
*major_cuda_compute_capability = 0;
*minor_cuda_compute_capability = 0;
}
}
}
}
result = fnNvmlShutdown();
if (NVML_SUCCESS != result) {
return false;
}
return true;
}
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_CONFIG_NVML_INFO_H_
#define GPU_CONFIG_NVML_INFO_H_
#include "build/build_config.h"
#include <stdint.h>
#include <string>
// Queries driver version and places it into driver_version. Writes
// major_cuda_compute_capability and minor_cuda_compute_capability of the GPU
// matching pci_device_id if one is found, or writes 0 into these outputs
// otherwise. Returns true on success.
bool GetNvmlDeviceInfo(uint32_t pci_device_id,
std::string* driver_version,
int* major_cuda_compute_capability,
int* minor_cuda_compute_capability);
#endif // GPU_CONFIG_NVML_INFO_H_
\ No newline at end of file
...@@ -448,7 +448,7 @@ ...@@ -448,7 +448,7 @@
}, },
{ {
"id": 59, "id": 59,
"description": "NVidia driver 8.15.11.8593 is crashy on Windows", "description": "NVidia driver 185.93 is crashy on Windows",
"cr_bugs": [155749], "cr_bugs": [155749],
"os": { "os": {
"type": "win" "type": "win"
...@@ -456,7 +456,7 @@ ...@@ -456,7 +456,7 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "=", "op": "=",
"value": "8.15.11.8593" "value": "185.93"
}, },
"features": [ "features": [
"accelerated_video_decode" "accelerated_video_decode"
...@@ -499,7 +499,7 @@ ...@@ -499,7 +499,7 @@
}, },
{ {
"id": 69, "id": 69,
"description": "NVIDIA driver 8.17.11.9621 is buggy with Stage3D baseline mode", "description": "NVIDIA driver 196.21 is buggy with Stage3D baseline mode",
"cr_bugs": [172771], "cr_bugs": [172771],
"os": { "os": {
"type": "win" "type": "win"
...@@ -507,7 +507,7 @@ ...@@ -507,7 +507,7 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "=", "op": "=",
"value": "8.17.11.9621" "value": "196.21"
}, },
"features": [ "features": [
"flash_stage3d_baseline" "flash_stage3d_baseline"
...@@ -515,7 +515,7 @@ ...@@ -515,7 +515,7 @@
}, },
{ {
"id": 70, "id": 70,
"description": "NVIDIA driver 8.17.11.8267 is buggy with Stage3D baseline mode", "description": "NVIDIA driver 182.67 is buggy with Stage3D baseline mode",
"cr_bugs": [172771], "cr_bugs": [172771],
"os": { "os": {
"type": "win" "type": "win"
...@@ -523,7 +523,7 @@ ...@@ -523,7 +523,7 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "=", "op": "=",
"value": "8.17.11.8267" "value": "182.67"
}, },
"features": [ "features": [
"flash_stage3d_baseline" "flash_stage3d_baseline"
...@@ -699,8 +699,8 @@ ...@@ -699,8 +699,8 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "between", "op": "between",
"value": "8.17.12.5729", "value": "257.29",
"value2": "8.17.12.8026" "value2": "280.26"
}, },
"features": [ "features": [
"accelerated_video_decode" "accelerated_video_decode"
...@@ -716,8 +716,8 @@ ...@@ -716,8 +716,8 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "between", "op": "between",
"value": "9.18.13.783", "value": "307.83",
"value2": "9.18.13.1090" "value2": "310.90"
}, },
"features": [ "features": [
"accelerated_video_decode" "accelerated_video_decode"
...@@ -1429,7 +1429,7 @@ ...@@ -1429,7 +1429,7 @@
"vendor_id": "0x10de", "vendor_id": "0x10de",
"driver_version": { "driver_version": {
"op": "<=", "op": "<=",
"value": "8.17.12.6973" "value": "269.73"
}, },
"features": [ "features": [
"accelerated_webgl2" "accelerated_webgl2"
......
...@@ -19,6 +19,7 @@ struct GpuDevice { ...@@ -19,6 +19,7 @@ struct GpuDevice {
string driver_vendor; string driver_vendor;
string driver_version; string driver_version;
string driver_date; string driver_date;
int32 cuda_compute_capability_major;
}; };
// gpu::VideoCodecProfile // gpu::VideoCodecProfile
......
...@@ -16,6 +16,7 @@ bool StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice>::Read( ...@@ -16,6 +16,7 @@ bool StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice>::Read(
out->vendor_id = data.vendor_id(); out->vendor_id = data.vendor_id();
out->device_id = data.device_id(); out->device_id = data.device_id();
out->active = data.active(); out->active = data.active();
out->cuda_compute_capability_major = data.cuda_compute_capability_major();
return data.ReadVendorString(&out->vendor_string) && return data.ReadVendorString(&out->vendor_string) &&
data.ReadDeviceString(&out->device_string) && data.ReadDeviceString(&out->device_string) &&
data.ReadDriverVendor(&out->driver_vendor) && data.ReadDriverVendor(&out->driver_vendor) &&
......
...@@ -54,6 +54,11 @@ struct StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice> { ...@@ -54,6 +54,11 @@ struct StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice> {
static const std::string& driver_date(const gpu::GPUInfo::GPUDevice& input) { static const std::string& driver_date(const gpu::GPUInfo::GPUDevice& input) {
return input.driver_date; return input.driver_date;
} }
static int cuda_compute_capability_major(
const gpu::GPUInfo::GPUDevice& input) {
return input.cuda_compute_capability_major;
}
}; };
template <> template <>
......
Copyright 1993-2017 NVIDIA Corporation. All rights reserved.
NOTICE TO USER:
This source code is subject to NVIDIA ownership rights under U.S. and
international Copyright laws. Users and possessors of this source code
are hereby granted a nonexclusive, royalty-free license to use this code
in individual and commercial software.
NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOURCE CODE.
U.S. Government End Users. This source code is a "commercial item" as
that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of
"commercial computer software" and "commercial computer software
documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995)
and is provided to the U.S. Government only as a commercial end item.
Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
source code with only those rights set forth herein.
Any use of this source code in individual and commercial software must
include, in the user documentation and internal comments to the code,
the above Disclaimer and U.S. Government End Users Notice.
kbr@chromium.org
zmo@chromium.org
Name: NVIDIA Management Library
Short Name: nvml
URL: https://developer.nvidia.com/nvidia-management-library-nvml
Version: 9.1.85
License: NVML license
License File: LICENSE
Security Critical: yes
Description:
This is a header file for interfacing with the NVML library that ships as a part
of NVIDIA proprietary drivers on Windows. The library can be used to query GPU
hardware and GPU driver information. Chromium loads the NVML library dynamically
and uses it for whitelisting and blacklisting purposes on Windows.
Points of contact at NVIDIA:
oetuaho@nvidia.com
amalp@nvidia.com
Local Modifications:
Trailing whitespace has been trimmed from the header file.
This diff is collapsed.
...@@ -461,6 +461,9 @@ PATH_SPECIFIC_WHITELISTED_LICENSES = { ...@@ -461,6 +461,9 @@ PATH_SPECIFIC_WHITELISTED_LICENSES = {
'third_party/modp_b64': [ 'third_party/modp_b64': [
'UNKNOWN', 'UNKNOWN',
], ],
'third_party/nvml': [
'UNKNOWN',
],
# Missing license headers in openh264 sources: https://github.com/cisco/openh264/issues/2233 # Missing license headers in openh264 sources: https://github.com/cisco/openh264/issues/2233
'third_party/openh264/src': [ 'third_party/openh264/src': [
'UNKNOWN', 'UNKNOWN',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment