implement gpu driver version for nvidia

This commit is contained in:
Junkui Zhang 2025-07-17 19:30:49 +08:00
parent 32488e1e2d
commit 432d11f57b
2 changed files with 112 additions and 7 deletions

View file

@ -32,6 +32,7 @@ pub(crate) struct DirectXRenderer {
/// Direct3D objects
#[derive(Clone)]
pub(crate) struct DirectXDevices {
adapter: IDXGIAdapter1,
dxgi_factory: IDXGIFactory6,
#[cfg(not(feature = "enable-renderdoc"))]
dxgi_device: IDXGIDevice,
@ -97,6 +98,7 @@ impl DirectXDevices {
let dxgi_device: IDXGIDevice = device.cast()?;
Ok(Self {
adapter,
dxgi_factory,
#[cfg(not(feature = "enable-renderdoc"))]
dxgi_device,
@ -396,6 +398,34 @@ impl DirectXRenderer {
}
Ok(())
}
pub(crate) fn gpu_specs(&self) -> Result<GpuSpecs> {
let desc = unsafe { self.devices.adapter.GetDesc1() }?;
let is_software_emulated = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE.0 as u32) != 0;
let device_name = String::from_utf16_lossy(&desc.Description)
.trim_matches(char::from(0))
.to_string();
let driver_name = match desc.VendorId {
0x10DE => "NVIDIA Corporation".to_string(),
0x1002 => "AMD Corporation".to_string(),
0x8086 => "Intel Corporation".to_string(),
_ => "Unknown Vendor".to_string(),
};
let driver_version = match desc.VendorId {
0x10DE => nvidia::get_driver_version().context("Failed to get NVIDIA driver info"),
0x1002 => Err(anyhow::anyhow!("AMD driver info not implemented yet")),
0x8086 => Err(anyhow::anyhow!("Intel driver info not implemented yet")),
_ => Err(anyhow::anyhow!("Unknown vendor detected.")),
}
.log_err()
.unwrap_or("Unknown Driver".to_string());
Ok(GpuSpecs {
is_software_emulated,
device_name,
driver_name,
driver_info: driver_version,
})
}
}
impl DirectXResources {
@ -936,12 +966,11 @@ fn get_adapter(dxgi_factory: &IDXGIFactory6) -> Result<IDXGIAdapter1> {
dxgi_factory
.EnumAdapterByGpuPreference(adapter_index, DXGI_GPU_PREFERENCE_MINIMUM_POWER)
}?;
{
let desc = unsafe { adapter.GetDesc1() }?;
println!(
"Select GPU: {}",
String::from_utf16_lossy(&desc.Description)
);
if let Ok(desc) = unsafe { adapter.GetDesc1() } {
let gpu_name = String::from_utf16_lossy(&desc.Description)
.trim_matches(char::from(0))
.to_string();
log::info!("Using GPU: {}", gpu_name);
}
// Check to see whether the adapter supports Direct3D 11, but don't
// create the actual device yet.
@ -1339,3 +1368,78 @@ mod shader_resources {
}
}
}
mod nvidia {
use std::os::raw::{c_char, c_int, c_uint};
use anyhow::{Context, Result};
use windows::{
Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA},
core::s,
};
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L180
const NVAPI_SHORT_STRING_MAX: usize = 64;
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L235
#[allow(non_camel_case_types)]
type NvAPI_ShortString = [c_char; NVAPI_SHORT_STRING_MAX];
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi.h#L87
#[allow(non_camel_case_types)]
type NvAPI_Initialize_t = unsafe extern "C" fn() -> c_int;
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L447
#[allow(non_camel_case_types)]
type NvAPI_SYS_GetDriverAndBranchVersion_t = unsafe extern "C" fn(
driver_version: *mut c_uint,
build_branch_string: *mut NvAPI_ShortString,
) -> c_int;
pub(super) fn get_driver_version() -> Result<String> {
unsafe {
// Try to load the NVIDIA driver DLL
let nvidia_dll = LoadLibraryA(s!("nvapi64.dll")).context("Can't load nvapi64.dll")?;
let nvapi_query_addr = GetProcAddress(nvidia_dll, s!("nvapi_QueryInterface"))
.ok_or_else(|| anyhow::anyhow!("Failed to get nvapi_QueryInterface address"))?;
let nvapi_query: extern "C" fn(u32) -> *mut () = std::mem::transmute(nvapi_query_addr);
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L33
let nvapi_init_ptr = nvapi_query(0x0150e828);
if nvapi_init_ptr.is_null() {
anyhow::bail!("Failed to get NVIDIA API function pointer");
}
let nvapi_init: NvAPI_Initialize_t = std::mem::transmute(nvapi_init_ptr);
let result = nvapi_init();
if result != 0 {
anyhow::bail!("Failed to initialize NVIDIA API, error code: {}", result);
}
// https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L41
let nvapi_get_driver_version_ptr = nvapi_query(0x2926aaad);
if nvapi_get_driver_version_ptr.is_null() {
anyhow::bail!("Failed to get NVIDIA driver version function pointer");
}
let nvapi_get_driver_version: NvAPI_SYS_GetDriverAndBranchVersion_t =
std::mem::transmute(nvapi_get_driver_version_ptr);
let mut driver_version: c_uint = 0;
let mut build_branch_string: NvAPI_ShortString = [0; NVAPI_SHORT_STRING_MAX];
let result = nvapi_get_driver_version(
&mut driver_version as *mut c_uint,
&mut build_branch_string as *mut NvAPI_ShortString,
);
if result != 0 {
anyhow::bail!(
"Failed to get NVIDIA driver version, error code: {}",
result
);
}
let major = driver_version / 100;
let minor = driver_version % 100;
Ok(format!("{}.{}", major, minor))
}
}
}

View file

@ -104,6 +104,7 @@ impl WindowsWindowState {
let restore_from_minimized = None;
// let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
let renderer = DirectXRenderer::new(gpu_context, hwnd)?;
println!("GPU specs: {:#?}", renderer.gpu_specs());
let callbacks = Callbacks::default();
let input_handler = None;
let pending_surrogate = None;
@ -801,7 +802,7 @@ impl PlatformWindow for WindowsWindow {
}
fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
// todo(windows)
// There is no such thing on Windows.
}
}