use std::{ptr, fmt};
use void::{Void, ResultVoidExt};
use sys::gpu::{self, pstate, clock, power, cooler, thermal, display};
use sys::{self, driverapi, i2c};
use types::{Kibibytes, KilohertzDelta, Kilohertz2Delta, Microvolts, Percentage, Percentage1000, RawConversion};
use thermal::CoolerLevel;
use clock::{ClockDomain, VfpMask};
use pstate::PState;
#[derive(Debug)]
pub struct PhysicalGpu(sys::handles::NvPhysicalGpuHandle);
unsafe impl Send for PhysicalGpu { }
pub use sys::gpu::{SystemType, PerformanceDecreaseReason};
pub use sys::gpu::private::{RamType, RamMaker, Foundry, VendorId as Vendor};
pub use sys::gpu::clock::ClockFrequencyType;
pub use sys::gpu::display::{ConnectedIdsFlags, DisplayIdsFlags, MonitorConnectorType};
pub type ClockFrequencies = <sys::gpu::clock::NV_GPU_CLOCK_FREQUENCIES as RawConversion>::Target;
pub type Utilizations = <pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX as RawConversion>::Target;
impl PhysicalGpu {
pub fn handle(&self) -> &sys::handles::NvPhysicalGpuHandle {
&self.0
}
pub fn enumerate() -> sys::Result<Vec<Self>> {
trace!("gpu.enumerate()");
let mut handles = [Default::default(); sys::types::NVAPI_MAX_PHYSICAL_GPUS];
let mut len = 0;
match unsafe { gpu::NvAPI_EnumPhysicalGPUs(&mut handles, &mut len) } {
sys::status::NVAPI_NVIDIA_DEVICE_NOT_FOUND => Ok(Vec::new()),
status => sys::status_result(status).map(move |_| handles[..len as usize].iter().cloned().map(PhysicalGpu).collect()),
}
}
pub fn tachometer(&self) -> sys::Result<u32> {
trace!("gpu.tachometer()");
let mut out = 0;
unsafe {
sys::status_result(cooler::NvAPI_GPU_GetTachReading(self.0, &mut out))
.map(move |_| out)
}
}
pub fn short_name(&self) -> sys::Result<String> {
trace!("gpu.short_name()");
let mut str = sys::types::short_string();
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetShortName(self.0, &mut str))
.map(|_| str.convert_raw().void_unwrap())
}
}
pub fn full_name(&self) -> sys::Result<String> {
trace!("gpu.full_name()");
let mut str = sys::types::short_string();
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetFullName(self.0, &mut str))
.map(|_| str.convert_raw().void_unwrap())
}
}
pub fn vbios_version_string(&self) -> sys::Result<String> {
trace!("gpu.vbios_version_string()");
let mut str = sys::types::short_string();
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetVbiosVersionString(self.0, &mut str))
.map(|_| str.convert_raw().void_unwrap())
}
}
pub fn driver_model(&self) -> sys::Result<DriverModel> {
trace!("gpu.driver_model()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GetDriverModel(self.0, &mut value))
.map(|_| DriverModel::new(value))
}
}
pub fn gpu_id(&self) -> sys::Result<u32> {
trace!("gpu.gpu_id()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GetGPUIDFromPhysicalGPU(self.0, &mut value))
.map(|_| value)
}
}
pub fn pci_identifiers(&self) -> sys::Result<PciIdentifiers> {
trace!("gpu.pci_identifiers()");
let mut pci = PciIdentifiers::default();
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetPCIIdentifiers(self.0, &mut pci.device_id, &mut pci.subsystem_id, &mut pci.revision_id, &mut pci.ext_device_id))
.map(|_| pci)
}
}
pub fn board_number(&self) -> sys::Result<[u8; 0x10]> {
trace!("gpu.board_number()");
let mut data = gpu::NV_BOARD_INFO::zeroed();
data.version = gpu::NV_BOARD_INFO_VER;
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetBoardInfo(self.0, &mut data))
.map(|_| data.BoardNum)
}
}
pub fn system_type(&self) -> sys::Result<SystemType> {
trace!("gpu.system_type()");
let mut ty = gpu::NV_SYSTEM_TYPE_UNKNOWN;
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetSystemType(self.0, &mut ty))
.and_then(|_| gpu::SystemType::from_raw(ty).map_err(From::from))
}
}
pub fn core_count(&self) -> sys::Result<u32> {
trace!("gpu.core_count()");
let mut value = 0;
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetGpuCoreCount(self.0, &mut value))
.map(|_| value)
}
}
pub fn shader_pipe_count(&self) -> sys::Result<u32> {
trace!("gpu.shader_pipe_count()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetShaderPipeCount(self.0, &mut value))
.map(|_| value)
}
}
pub fn shader_sub_pipe_count(&self) -> sys::Result<u32> {
trace!("gpu.shader_sub_pipe_count()");
let mut value = 0;
unsafe {
sys::status_result(gpu::NvAPI_GPU_GetShaderSubPipeCount(self.0, &mut value))
.map(|_| value)
}
}
pub fn ram_type(&self) -> sys::Result<RamType> {
trace!("gpu.ram_type()");
let mut value = gpu::private::NV_GPU_RAM_UNKNOWN;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetRamType(self.0, &mut value))
.and_then(|_| gpu::private::RamType::from_raw(value).map_err(From::from))
}
}
pub fn ram_maker(&self) -> sys::Result<RamMaker> {
trace!("gpu.ram_maker()");
let mut value = gpu::private::NV_GPU_RAM_MAKER_UNKNOWN;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetRamMaker(self.0, &mut value))
.and_then(|_| gpu::private::RamMaker::from_raw(value).map_err(From::from))
}
}
pub fn ram_bus_width(&self) -> sys::Result<u32> {
trace!("gpu.ram_bus_width()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetRamBusWidth(self.0, &mut value))
.map(|_| value)
}
}
pub fn ram_bank_count(&self) -> sys::Result<u32> {
trace!("gpu.ram_bank_count()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetRamBankCount(self.0, &mut value))
.map(|_| value)
}
}
pub fn ram_partition_count(&self) -> sys::Result<u32> {
trace!("gpu.ram_partition_count()");
let mut value = 0;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetPartitionCount(self.0, &mut value))
.map(|_| value)
}
}
pub fn foundry(&self) -> sys::Result<Foundry> {
trace!("gpu.foundry()");
let mut value = gpu::private::NV_GPU_FOUNDRY_UNKNOWN;
unsafe {
sys::status_result(gpu::private::NvAPI_GPU_GetFoundry(self.0, &mut value))
.and_then(|_| gpu::private::Foundry::from_raw(value).map_err(From::from))
}
}
pub fn memory_info(&self) -> sys::Result<MemoryInfo> {
trace!("gpu.memory_info()");
let mut data = driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO::zeroed();
data.version = driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO_VER;
sys::status_result(unsafe { driverapi::NvAPI_GPU_GetMemoryInfo(self.0, &mut data) })
.map(|_| data.convert_raw().void_unwrap())
}
pub fn clock_frequencies(&self, clock_type: ClockFrequencyType) -> sys::Result<ClockFrequencies> {
trace!("gpu.clock_frequencies({:?})", clock_type);
let mut clocks = clock::NV_GPU_CLOCK_FREQUENCIES::zeroed();
clocks.version = clock::NV_GPU_CLOCK_FREQUENCIES_VER;
clocks.set_ClockType(clock_type.raw());
sys::status_result(unsafe { clock::NvAPI_GPU_GetAllClockFrequencies(self.0, &mut clocks) })
.map(|_| clocks.convert_raw().void_unwrap())
}
pub fn current_pstate(&self) -> sys::Result<::pstate::PState> {
trace!("gpu.current_pstate()");
let mut pstate = 0;
sys::status_result(unsafe { pstate::NvAPI_GPU_GetCurrentPstate(self.0, &mut pstate) })?;
::pstate::PState::from_raw(pstate).map_err(From::from)
}
pub fn pstates(&self) -> sys::Result<<pstate::NV_GPU_PERF_PSTATES20_INFO as RawConversion>::Target> {
trace!("gpu.pstates()");
let mut info = pstate::NV_GPU_PERF_PSTATES20_INFO::zeroed();
info.version = pstate::NV_GPU_PERF_PSTATES20_INFO_VER;
sys::status_result(unsafe { pstate::NvAPI_GPU_GetPstates20(self.0, &mut info) })
.and_then(|_| info.convert_raw().map_err(From::from))
}
pub fn set_pstates<I: Iterator<Item=(PState, ClockDomain, KilohertzDelta)>>(&self, deltas: I) -> sys::Result<()> {
trace!("gpu.set_pstates()");
use std::collections::BTreeMap;
let mut info = pstate::NV_GPU_PERF_PSTATES20_INFO::zeroed();
info.version = pstate::NV_GPU_PERF_PSTATES20_INFO_VER;
let mut map: BTreeMap<PState, (usize, usize)> = Default::default();
for (pstate, clock, delta) in deltas {
trace!("gpu.set_pstate({:?}, {:?}, {:?})", pstate, clock, delta);
let pstates = map.len();
let map = map.entry(pstate).or_insert((pstates, 0));
let entry = &mut info.pstates[map.0];
entry.pstateId = pstate.raw();
let entry = &mut entry.clocks[map.1];
entry.domainId = clock.raw();
entry.freqDelta_kHz.value = delta.0;
map.1 += 1;
}
info.numPstates = map.len() as _;
info.numClocks = map.iter().map(|v| (v.1).1).max().unwrap_or(0) as _;
sys::status_result(unsafe { pstate::private::NvAPI_GPU_SetPstates20(self.0, &info) })
}
pub fn dynamic_pstates_info(&self) -> sys::Result<Utilizations> {
trace!("gpu.dynamic_pstates_info()");
let mut info = pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX::zeroed();
info.version = pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX_VER;
sys::status_result(unsafe { pstate::NvAPI_GPU_GetDynamicPstatesInfoEx(self.0, &mut info) })
.and_then(|_| info.convert_raw().map_err(From::from))
}
pub fn usages(&self) -> sys::Result<<clock::private::NV_USAGES_INFO as RawConversion>::Target> {
trace!("gpu.usages()");
let mut usages = clock::private::NV_USAGES_INFO::zeroed();
usages.version = clock::private::NV_USAGES_INFO_VER;
sys::status_result(unsafe { clock::private::NvAPI_GPU_GetUsages(self.0, &mut usages) })
.and_then(|_| usages.convert_raw().map_err(From::from))
}
pub fn vfp_mask(&self) -> sys::Result<<clock::private::NV_CLOCK_MASKS as RawConversion>::Target> {
trace!("gpu.vfp_mask()");
let mut data = clock::private::NV_CLOCK_MASKS::zeroed();
data.version = clock::private::NV_CLOCK_MASKS_VER;
sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostMask(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn vfp_table(&self, mask: [u32; 4]) -> sys::Result<<clock::private::NV_CLOCK_TABLE as RawConversion>::Target> {
trace!("gpu.vfp_table({:?})", mask);
let mut data = clock::private::NV_CLOCK_TABLE::zeroed();
data.version = clock::private::NV_CLOCK_TABLE_VER;
data.mask = mask;
sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostTable(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_vfp_table<I: Iterator<Item=(usize, Kilohertz2Delta)>, M: Iterator<Item=(usize, Kilohertz2Delta)>>(&self, mask: [u32; 4], clocks: I, memory: M) -> sys::Result<()> {
trace!("gpu.set_vfp_table({:?})", mask);
let mut data = clock::private::NV_CLOCK_TABLE::zeroed();
data.version = clock::private::NV_CLOCK_TABLE_VER;
data.mask = mask;
for (i, delta) in clocks {
trace!("gpu.set_vfp_table({:?}, {:?})", i, delta);
data.gpuDeltas[i].freqDeltaKHz = delta.0;
VfpMask::set_bit(&mut data.mask, i);
}
for (i, delta) in memory {
data.memFilled[i] = 1;
data.memDeltas[i] = delta.0;
}
sys::status_result(unsafe { clock::private::NvAPI_GPU_SetClockBoostTable(self.0, &data) })
}
pub fn vfp_ranges(&self) -> sys::Result<<clock::private::NV_CLOCK_RANGES as RawConversion>::Target> {
trace!("gpu.vfp_ranges()");
let mut data = clock::private::NV_CLOCK_RANGES::zeroed();
data.version = clock::private::NV_CLOCK_RANGES_VER;
sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostRanges(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn vfp_locks(&self) -> sys::Result<<clock::private::NV_CLOCK_LOCK as RawConversion>::Target> {
trace!("gpu.vfp_locks()");
let mut data = clock::private::NV_CLOCK_LOCK::zeroed();
data.version = clock::private::NV_CLOCK_LOCK_VER;
sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostLock(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_vfp_locks<I: Iterator<Item=(usize, Option<Microvolts>)>>(&self, values: I) -> sys::Result<()> {
trace!("gpu.set_vfp_locks()");
use clock::ClockLockMode;
let mut data = clock::private::NV_CLOCK_LOCK::zeroed();
data.version = clock::private::NV_CLOCK_LOCK_VER;
for (i, (id, voltage)) in values.enumerate() {
trace!("gpu.set_vfp_lock({:?}, {:?})", id, voltage);
data.count += 1;
let entry = &mut data.entries[i];
entry.id = id as _;
if let Some(voltage) = voltage {
entry.mode = ClockLockMode::Manual.raw();
entry.voltage_uV = voltage.0;
} else {
}
}
sys::status_result(unsafe { clock::private::NvAPI_GPU_SetClockBoostLock(self.0, &data) })
}
pub fn vfp_curve(&self, mask: [u32; 4]) -> sys::Result<<power::private::NV_VFP_CURVE as RawConversion>::Target> {
trace!("gpu.vfp_curve({:?})", mask);
let mut data = power::private::NV_VFP_CURVE::zeroed();
data.version = power::private::NV_VFP_CURVE_VER;
data.mask = mask;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetVFPCurve(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn core_voltage(&self) -> sys::Result<<power::private::NV_VOLTAGE_STATUS as RawConversion>::Target> {
trace!("gpu.core_voltage()");
let mut data = power::private::NV_VOLTAGE_STATUS::zeroed();
data.version = power::private::NV_VOLTAGE_STATUS_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetCurrentVoltage(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn core_voltage_boost(&self) -> sys::Result<<power::private::NV_VOLTAGE_BOOST_PERCENT as RawConversion>::Target> {
trace!("gpu.core_voltage_boost()");
let mut data = power::private::NV_VOLTAGE_BOOST_PERCENT::zeroed();
data.version = power::private::NV_VOLTAGE_BOOST_PERCENT_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetCoreVoltageBoostPercent(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_core_voltage_boost(&self, value: Percentage) -> sys::Result<()> {
trace!("gpu.set_core_voltage_boost({:?})", value);
let mut data = power::private::NV_VOLTAGE_BOOST_PERCENT::zeroed();
data.version = power::private::NV_VOLTAGE_BOOST_PERCENT_VER;
data.percent = value.0;
sys::status_result(unsafe { power::private::NvAPI_GPU_SetCoreVoltageBoostPercent(self.0, &data) })
}
pub fn power_usage(&self) -> sys::Result<<power::private::NV_GPU_POWER_TOPO as RawConversion>::Target> {
trace!("gpu.power_usage()");
let mut data = power::private::NV_GPU_POWER_TOPO::zeroed();
data.version = power::private::NV_GPU_POWER_TOPO_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerTopologyGetStatus(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn power_limit_info(&self) -> sys::Result<<power::private::NV_GPU_POWER_INFO as RawConversion>::Target> {
trace!("gpu.power_limit_info()");
let mut data = power::private::NV_GPU_POWER_INFO::zeroed();
data.version = power::private::NV_GPU_POWER_INFO_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesGetInfo(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn power_limit(&self) -> sys::Result<<power::private::NV_GPU_POWER_STATUS as RawConversion>::Target> {
trace!("gpu.power_limit()");
let mut data = power::private::NV_GPU_POWER_STATUS::zeroed();
data.version = power::private::NV_GPU_POWER_STATUS_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesGetStatus(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_power_limit<I: Iterator<Item=Percentage1000>>(&self, values: I) -> sys::Result<()> {
trace!("gpu.set_power_limit()");
let mut data = power::private::NV_GPU_POWER_STATUS::zeroed();
data.version = power::private::NV_GPU_POWER_STATUS_VER;
for (entry, v) in data.entries.iter_mut().zip(values) {
trace!("gpu.set_power_limit({:?})", v);
entry.power = v.0;
data.count += 1;
}
sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesSetStatus(self.0, &data) })
}
pub fn thermal_settings(&self, index: Option<u32>) -> sys::Result<<thermal::NV_GPU_THERMAL_SETTINGS as RawConversion>::Target> {
trace!("gpu.thermal_settings({:?})", index);
let mut data = thermal::NV_GPU_THERMAL_SETTINGS::zeroed();
data.version = thermal::NV_GPU_THERMAL_SETTINGS_VER;
sys::status_result(unsafe { thermal::NvAPI_GPU_GetThermalSettings(self.0, index.unwrap_or(thermal::NVAPI_THERMAL_TARGET_ALL as _), &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn thermal_limit_info(&self) -> sys::Result<<thermal::private::NV_GPU_THERMAL_INFO as RawConversion>::Target> {
trace!("gpu.thermal_limit_info()");
let mut data = thermal::private::NV_GPU_THERMAL_INFO::zeroed();
data.version = thermal::private::NV_GPU_THERMAL_INFO_VER;
sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesGetInfo(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn thermal_limit(&self) -> sys::Result<<thermal::private::NV_GPU_THERMAL_LIMIT as RawConversion>::Target> {
trace!("gpu.thermal_limit()");
let mut data = thermal::private::NV_GPU_THERMAL_LIMIT::zeroed();
data.version = thermal::private::NV_GPU_THERMAL_LIMIT_VER;
sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesGetLimit(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_thermal_limit<I: Iterator<Item=::thermal::ThermalLimit>>(&self, value: I) -> sys::Result<()> {
trace!("gpu.set_thermal_limit()");
let mut data = thermal::private::NV_GPU_THERMAL_LIMIT::zeroed();
data.version = thermal::private::NV_GPU_THERMAL_LIMIT_VER;
for (entry, v) in data.entries.iter_mut().zip(value) {
trace!("gpu.set_thermal_limit({:?})", v);
entry.controller = v.controller.raw();
entry.value = v.value.0 as _;
entry.flags = v.flags;
data.flags += 1;
}
sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesSetLimit(self.0, &data) })
}
pub fn cooler_settings(&self, index: Option<u32>) -> sys::Result<<cooler::private::NV_GPU_COOLER_SETTINGS as RawConversion>::Target> {
trace!("gpu.cooler_settings({:?})", index);
let mut data = cooler::private::NV_GPU_COOLER_SETTINGS::zeroed();
data.version = cooler::private::NV_GPU_COOLER_SETTINGS_VER;
sys::status_result(unsafe { cooler::private::NvAPI_GPU_GetCoolerSettings(self.0, index.unwrap_or(cooler::private::NVAPI_COOLER_TARGET_ALL as _), &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn set_cooler_levels<I: Iterator<Item=CoolerLevel>>(&self, index: Option<u32>, values: I) -> sys::Result<()> {
trace!("gpu.set_cooler_levels({:?})", index);
let mut data = cooler::private::NV_GPU_SETCOOLER_LEVEL::zeroed();
data.version = cooler::private::NV_GPU_SETCOOLER_LEVEL_VER;
for (entry, level) in data.cooler.iter_mut().zip(values) {
trace!("gpu.set_cooler_level({:?})", level);
entry.currentLevel = level.level.0;
entry.currentPolicy = level.policy.raw();
}
sys::status_result(unsafe { cooler::private::NvAPI_GPU_SetCoolerLevels(self.0, index.unwrap_or(cooler::private::NVAPI_COOLER_TARGET_ALL as _), &mut data) })
}
pub fn restore_cooler_settings(&self, index: &[u32]) -> sys::Result<()> {
trace!("gpu.restore_cooler_settings({:?})", index);
let ptr = if index.is_empty() { ptr::null() } else { index.as_ptr() };
sys::status_result(unsafe { cooler::private::NvAPI_GPU_RestoreCoolerSettings(self.0, ptr, index.len() as u32) })
}
pub fn cooler_policy_table(&self, index: u32, policy: ::thermal::CoolerPolicy) -> sys::Result<<cooler::private::NV_GPU_COOLER_POLICY_TABLE as RawConversion>::Target> {
trace!("gpu.cooler_policy_table({:?})", index);
let mut data = cooler::private::NV_GPU_COOLER_POLICY_TABLE::zeroed();
data.version = cooler::private::NV_GPU_COOLER_POLICY_TABLE_VER;
data.policy = policy.raw();
let mut count = 0;
sys::status_result(unsafe { cooler::private::NvAPI_GPU_GetCoolerPolicyTable(self.0, index, &mut data, &mut count) })
.and_then(|_| data.convert_raw().map_err(From::from)).map(|mut c| {
c.levels.truncate(count as usize);
c
})
}
pub fn set_cooler_policy_table(&self, index: u32, value: &<cooler::private::NV_GPU_COOLER_POLICY_TABLE as RawConversion>::Target) -> sys::Result<()> {
trace!("gpu.set_cooler_policy_table({:?}, {:?})", index, value);
let mut data = cooler::private::NV_GPU_COOLER_POLICY_TABLE::zeroed();
data.version = cooler::private::NV_GPU_COOLER_POLICY_TABLE_VER;
sys::status_result(unsafe { cooler::private::NvAPI_GPU_SetCoolerPolicyTable(self.0, index, &data, value.levels.len() as u32) })
}
pub fn restore_cooler_policy_table(&self, index: &[u32], policy: ::thermal::CoolerPolicy) -> sys::Result<()> {
trace!("gpu.restore_cooler_policy_table({:?}, {:?})", index, policy);
let ptr = if index.is_empty() { ptr::null() } else { index.as_ptr() };
sys::status_result(unsafe { cooler::private::NvAPI_GPU_RestoreCoolerPolicyTable(self.0, ptr, index.len() as u32, policy.raw()) })
}
pub fn perf_info(&self) -> sys::Result<<power::private::NV_GPU_PERF_INFO as RawConversion>::Target> {
trace!("gpu.perf_info()");
let mut data = power::private::NV_GPU_PERF_INFO::zeroed();
data.version = power::private::NV_GPU_PERF_INFO_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_PerfPoliciesGetInfo(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn perf_status(&self) -> sys::Result<<power::private::NV_GPU_PERF_STATUS as RawConversion>::Target> {
trace!("gpu.perf_status()");
let mut data = power::private::NV_GPU_PERF_STATUS::zeroed();
data.version = power::private::NV_GPU_PERF_STATUS_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_PerfPoliciesGetStatus(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn voltage_domains_status(&self) -> sys::Result<<power::private::NV_VOLT_STATUS as RawConversion>::Target> {
trace!("gpu.voltage_domains_status()");
let mut data = power::private::NV_VOLT_STATUS::zeroed();
data.version = power::private::NV_VOLT_STATUS_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltageDomainsStatus(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn voltage_step(&self) -> sys::Result<<power::private::NV_VOLT_STATUS as RawConversion>::Target> {
trace!("gpu.voltage_step()");
let mut data = power::private::NV_VOLT_STATUS::zeroed();
data.version = power::private::NV_VOLT_STATUS_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltageStep(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn voltage_table(&self) -> sys::Result<<power::private::NV_VOLT_TABLE as RawConversion>::Target> {
trace!("gpu.voltage_table()");
let mut data = power::private::NV_VOLT_TABLE::zeroed();
data.version = power::private::NV_VOLT_TABLE_VER;
sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltages(self.0, &mut data) })
.and_then(|_| data.convert_raw().map_err(From::from))
}
pub fn performance_decrease(&self) -> sys::Result<PerformanceDecreaseReason> {
trace!("gpu.performance_decrease()");
let mut data = gpu::NV_GPU_PERF_DECREASE_NONE;
sys::status_result(unsafe { gpu::NvAPI_GPU_GetPerfDecreaseInfo(self.0, &mut data) })
.map(|_| PerformanceDecreaseReason::from_bits_truncate(data))
}
pub fn display_ids_all(&self) -> sys::Result<Vec<<display::NV_GPU_DISPLAYIDS as RawConversion>::Target>> {
trace!("gpu.display_ids_all()");
let mut count = 0;
sys::status_result(unsafe { display::NvAPI_GPU_GetAllDisplayIds(self.0, ptr::null_mut(), &mut count) })?;
if count == 0 {
return Ok(Vec::new());
}
let mut data = display::NV_GPU_DISPLAYIDS::zeroed();
data.version = display::NV_GPU_DISPLAYIDS_VER;
let mut data = vec![data; count as usize];
sys::status_result(unsafe { display::NvAPI_GPU_GetAllDisplayIds(self.0, data.as_mut_ptr(), &mut count) })
.and_then(|_| data.into_iter().map(|v| v.convert_raw().map_err(From::from)).collect())
}
pub fn display_ids_connected(&self, flags: ConnectedIdsFlags) -> sys::Result<Vec<<display::NV_GPU_DISPLAYIDS as RawConversion>::Target>> {
trace!("gpu.display_ids_connected({:?})", flags);
let mut count = 0;
sys::status_result(unsafe { display::NvAPI_GPU_GetConnectedDisplayIds(self.0, ptr::null_mut(), &mut count, flags.bits()) })?;
if count == 0 {
return Ok(Vec::new());
}
let mut data = display::NV_GPU_DISPLAYIDS::zeroed();
data.version = display::NV_GPU_DISPLAYIDS_VER;
let mut data = vec![data; count as usize];
sys::status_result(unsafe { display::NvAPI_GPU_GetConnectedDisplayIds(self.0, data.as_mut_ptr(), &mut count, flags.bits()) })
.and_then(|_| data.into_iter().map(|v| v.convert_raw().map_err(From::from)).collect())
}
pub fn i2c_read(&self, display_mask: u32, port: Option<u8>, port_is_ddc: bool, address: u8, register: &[u8], bytes: &mut [u8], speed: i2c::I2cSpeed) -> sys::Result<usize> {
trace!("i2c_read({}, {:?}, {:?}, 0x{:02x}, {:?}, {:?})", display_mask, port, port_is_ddc, address, register, speed);
let mut data = i2c::NV_I2C_INFO::zeroed();
data.version = i2c::NV_I2C_INFO_VER;
data.displayMask = display_mask;
data.bIsDDCPort = if port_is_ddc { sys::NV_TRUE } else { sys::NV_FALSE } as _;
data.i2cDevAddress = address << 1;
data.pbI2cRegAddress = if register.is_empty() { ptr::null_mut() } else { register.as_ptr() as *mut _ };
data.regAddrSize = register.len() as _;
data.pbData = bytes.as_mut_ptr();
data.cbSize = bytes.len() as _;
data.i2cSpeed = i2c::NVAPI_I2C_SPEED_DEPRECATED;
data.i2cSpeedKhz = speed.raw();
if let Some(port) = port {
data.portId = port;
data.bIsPortIdSet = sys::NV_TRUE as _;
}
sys::status_result(unsafe { i2c::NvAPI_I2CRead(self.0, &mut data) })
.map(|_| data.cbSize as usize) }
pub fn i2c_write(&self, display_mask: u32, port: Option<u8>, port_is_ddc: bool, address: u8, register: &[u8], bytes: &[u8], speed: i2c::I2cSpeed) -> sys::Result<()> {
trace!("i2c_write({}, {:?}, {:?}, 0x{:02x}, {:?}, {:?})", display_mask, port, port_is_ddc, address, register, speed);
let mut data = i2c::NV_I2C_INFO::zeroed();
data.version = i2c::NV_I2C_INFO_VER;
data.displayMask = display_mask;
data.bIsDDCPort = if port_is_ddc { sys::NV_TRUE } else { sys::NV_FALSE } as _;
data.i2cDevAddress = address << 1;
data.pbI2cRegAddress = if register.is_empty() { ptr::null_mut() } else { register.as_ptr() as *mut _ };
data.regAddrSize = register.len() as _;
data.pbData = bytes.as_ptr() as *mut _;
data.cbSize = bytes.len() as _;
data.i2cSpeed = i2c::NVAPI_I2C_SPEED_DEPRECATED;
data.i2cSpeedKhz = speed.raw();
if let Some(port) = port {
data.portId = port;
data.bIsPortIdSet = sys::NV_TRUE as _;
}
sys::status_result(unsafe { i2c::NvAPI_I2CWrite(self.0, &mut data) })
.map(drop)
}
}
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct PciIdentifiers {
pub device_id: u32,
pub subsystem_id: u32,
pub revision_id: u32,
pub ext_device_id: u32,
}
impl fmt::Display for PciIdentifiers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:08x} - {:08x} - {:08x} - {:x}", self.device_id, self.subsystem_id, self.ext_device_id, self.revision_id)
}
}
impl PciIdentifiers {
pub fn vendor_id(&self) -> u16 {
self.ids().0
}
pub fn product_id(&self) -> u16 {
self.ids().1
}
pub fn ids(&self) -> (u16, u16) {
let pid = (self.device_id >> 16) as u16;
let vid = self.device_id as u16;
if vid == 0x10de && self.subsystem_id != 0 {
let spid = (self.subsystem_id >> 16) as u16;
(
self.subsystem_id as u16,
if spid == 0 {
pid
} else {
spid
}
)
} else {
(vid, pid)
}
}
pub fn vendor(&self) -> Result<Vendor, sys::ArgumentRangeError> {
Vendor::from_raw(self.vendor_id() as _)
}
}
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct MemoryInfo {
pub dedicated: Kibibytes,
pub dedicated_available: Kibibytes,
pub system: Kibibytes,
pub shared: Kibibytes,
pub dedicated_available_current: Kibibytes,
pub dedicated_evictions_size: Kibibytes,
pub dedicated_evictions: u32,
}
impl RawConversion for driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO {
type Target = MemoryInfo;
type Error = Void;
fn convert_raw(&self) -> Result<Self::Target, Self::Error> {
Ok(MemoryInfo {
dedicated: Kibibytes(self.dedicatedVideoMemory),
dedicated_available: Kibibytes(self.availableDedicatedVideoMemory),
system: Kibibytes(self.systemVideoMemory),
shared: Kibibytes(self.sharedSystemMemory),
dedicated_available_current: Kibibytes(self.curAvailableDedicatedVideoMemory),
dedicated_evictions_size: Kibibytes(self.dedicatedVideoMemoryEvictionsSize),
dedicated_evictions: self.dedicatedVideoMemoryEvictionCount,
})
}
}
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct DriverModel {
pub value: u32,
}
impl DriverModel {
pub fn new(value: u32) -> Self {
DriverModel {
value: value,
}
}
pub fn wddm(&self) -> (u8, u8) {
let major = ((self.value >> 12) & 0xf) as u8;
(
major,
if major == 2 { 0 } else { (self.value >> 8) as u8 & 0xf }
)
}
}
impl fmt::Display for DriverModel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let wddm = self.wddm();
write!(f, "WDDM {}.{:02}", wddm.0, wddm.1)
}
}
impl fmt::Debug for DriverModel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({:08x})", self, self.value)
}
}
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct DisplayId {
pub connector: MonitorConnectorType,
pub display_id: u32,
pub flags: DisplayIdsFlags,
}
impl RawConversion for display::NV_GPU_DISPLAYIDS {
type Target = DisplayId;
type Error = sys::ArgumentRangeError;
fn convert_raw(&self) -> Result<Self::Target, Self::Error> {
Ok(DisplayId {
connector: MonitorConnectorType::from_raw(self.connectorType)?,
display_id: self.displayId,
flags: DisplayIdsFlags::from_bits_truncate(self.flags),
})
}
}